diff --git a/packages/daemon/src/connection.js b/packages/daemon/src/connection.js index 1cc2614f09..58947cfd97 100644 --- a/packages/daemon/src/connection.js +++ b/packages/daemon/src/connection.js @@ -4,14 +4,16 @@ import { makeCapTP } from '@endo/captp'; import { mapWriter, mapReader } from '@endo/stream'; import { makeNetstringReader, makeNetstringWriter } from '@endo/netstring'; +/** @import { Stream, Reader, Writer } from '@endo/stream' */ + const textEncoder = new TextEncoder(); const textDecoder = new TextDecoder(); /** * @template TBootstrap * @param {string} name - * @param {import('@endo/stream').Stream} writer - * @param {import('@endo/stream').Stream} reader + * @param {Stream} writer + * @param {Stream} reader * @param {Promise} cancelled * @param {TBootstrap} bootstrap */ @@ -65,8 +67,8 @@ export const bytesToMessage = bytes => { /** * @template TBootstrap * @param {string} name - * @param {import('@endo/stream').Writer} bytesWriter - * @param {import('@endo/stream').Reader} bytesReader + * @param {Writer} bytesWriter + * @param {Reader} bytesReader * @param {Promise} cancelled * @param {TBootstrap} bootstrap */ diff --git a/packages/daemon/src/context.js b/packages/daemon/src/context.js index 85fe1a3e4d..c6c75c4710 100644 --- a/packages/daemon/src/context.js +++ b/packages/daemon/src/context.js @@ -2,6 +2,9 @@ import { makePromiseKit } from '@endo/promise-kit'; +/** @import { PromiseKit } from '@endo/promise-kit' */ +/** @import { Context } from './types.js' */ + export const makeContextMaker = ({ controllerForId, provideController }) => { /** * @param {string} id @@ -9,15 +12,11 @@ export const makeContextMaker = ({ controllerForId, provideController }) => { const makeContext = id => { let done = false; const { promise: cancelled, reject: rejectCancelled } = - /** @type {import('@endo/promise-kit').PromiseKit} */ ( - makePromiseKit() - ); + /** @type {PromiseKit} */ (makePromiseKit()); const { promise: disposed, resolve: resolveDisposed } = - /** @type {import('@endo/promise-kit').PromiseKit} */ ( - makePromiseKit() - ); + /** @type {PromiseKit} */ (makePromiseKit()); - /** @type {Map} */ + /** @type {Map} */ const dependents = new Map(); /** @type {Array<() => void>} */ const hooks = []; diff --git a/packages/daemon/src/daemon-node-powers.js b/packages/daemon/src/daemon-node-powers.js index 80cf51da24..53f7d41ec6 100644 --- a/packages/daemon/src/daemon-node-powers.js +++ b/packages/daemon/src/daemon-node-powers.js @@ -10,6 +10,24 @@ import { makePetStoreMaker } from './pet-store.js'; import { servePrivatePath } from './serve-private-path.js'; import { makeSerialJobs } from './serial-jobs.js'; +/** @import { Reader, Writer } from '@endo/stream' */ +/** @import { ERef, FarRef } from '@endo/eventual-send' */ +/** + * @import { + * Config, + * CryptoPowers, + * DaemonWorkerFacet, + * DaemonicPersistencePowers, + * DaemonicPowers, + * EndoReadable, + * FilePowers, + * Formula, + * NetworkPowers, + * SocketPowers, + * WorkerDaemonFacet, + * } from './types.js' + */ + const { quote: q } = assert; const textEncoder = new TextEncoder(); @@ -17,13 +35,13 @@ const textEncoder = new TextEncoder(); /** * @param {object} modules * @param {typeof import('net')} modules.net - * @returns {import('./types.js').SocketPowers} + * @returns {SocketPowers} */ export const makeSocketPowers = ({ net }) => { const serveListener = async (listen, cancelled) => { const [ - /** @type {Reader} */ readFrom, - /** @type {Writer} */ readFrom, + /** @type {Writer { }); }; - /** @type {import('./types.js').SocketPowers['servePort']} */ + /** @type {SocketPowers['servePort']} */ const servePort = async ({ port, host = '0.0.0.0', cancelled }) => serveListener( server => @@ -71,7 +89,7 @@ export const makeSocketPowers = ({ net }) => { cancelled, ); - /** @type {import('./types.js').SocketPowers['connectPort']} */ + /** @type {SocketPowers['connectPort']} */ const connectPort = ({ port, host }) => new Promise((resolve, reject) => { const conn = net.connect(port, host, err => { @@ -90,7 +108,7 @@ export const makeSocketPowers = ({ net }) => { }); }); - /** @type {import('./types.js').SocketPowers['servePath']} */ + /** @type {SocketPowers['servePath']} */ const servePath = async ({ path, cancelled }) => { const { connections } = await serveListener(server => { return new Promise((resolve, reject) => @@ -117,7 +135,7 @@ export const makeSocketPowers = ({ net }) => { /** * @param {object} modules * @param {typeof import('net')} modules.net - * @returns {import('./types.js').NetworkPowers} + * @returns {NetworkPowers} */ export const makeNetworkPowers = ({ net }) => { const { servePort, servePath, connectPort } = makeSocketPowers({ net }); @@ -131,7 +149,7 @@ export const makeNetworkPowers = ({ net }) => { })(); /** - * @param {import('@endo/far').FarRef} endoBootstrap + * @param {FarRef} endoBootstrap * @param {string} sockPath * @param {Promise} cancelled * @param {(error: Error) => void} exitWithError @@ -173,7 +191,7 @@ export const makeFilePowers = ({ fs, path: fspath }) => { /** * @param {string} path - * @returns {import('@endo/stream').Writer} + * @returns {Writer} */ const makeFileWriter = path => { const nodeWriteStream = fs.createWriteStream(path); @@ -258,7 +276,7 @@ export const makeFilePowers = ({ fs, path: fspath }) => { /** * @param {typeof import('crypto')} crypto - * @returns {import('./types.js').CryptoPowers} + * @returns {CryptoPowers} */ export const makeCryptoPowers = crypto => { const makeSha512 = () => { @@ -288,10 +306,10 @@ export const makeCryptoPowers = crypto => { }; /** - * @param {import('./types.js').FilePowers} filePowers - * @param {import('./types.js').CryptoPowers} cryptoPowers - * @param {import('./types.js').Config} config - * @returns {import('./types.js').DaemonicPersistencePowers} + * @param {FilePowers} filePowers + * @param {CryptoPowers} cryptoPowers + * @param {Config} config + * @returns {DaemonicPersistencePowers} */ export const makeDaemonicPersistencePowers = ( filePowers, @@ -352,7 +370,7 @@ export const makeDaemonicPersistencePowers = ( }, /** * @param {string} sha512 - * @returns {import('./types.js').EndoReadable} + * @returns {EndoReadable} */ fetch(sha512) { const storagePath = filePowers.joinPath(storageDirectoryPath, sha512); @@ -393,7 +411,7 @@ export const makeDaemonicPersistencePowers = ( /** * @param {string} formulaNumber - * @returns {Promise} + * @returns {Promise} */ const readFormula = async formulaNumber => { const { file: formulaPath } = makeFormulaPath(formulaNumber); @@ -414,7 +432,7 @@ export const makeDaemonicPersistencePowers = ( }; // Persist instructions for revival (this can be collected) - /** @type {import('./types.js').DaemonicPersistencePowers['writeFormula']} */ + /** @type {DaemonicPersistencePowers['writeFormula']} */ const writeFormula = async (formulaNumber, formula) => { const { directory, file } = makeFormulaPath(formulaNumber); // TODO Take care to write atomically with a rename here. @@ -432,9 +450,9 @@ export const makeDaemonicPersistencePowers = ( }; /** - * @param {import('./types.js').Config} config + * @param {Config} config * @param {import('url').fileURLToPath} fileURLToPath - * @param {import('./types.js').FilePowers} filePowers + * @param {FilePowers} filePowers * @param {typeof import('fs')} fs * @param {typeof import('child_process')} popen */ @@ -451,7 +469,7 @@ export const makeDaemonicControlPowers = ( /** * @param {string} workerId - * @param {import('./types.js').DaemonWorkerFacet} daemonWorkerFacet + * @param {DaemonWorkerFacet} daemonWorkerFacet * @param {Promise} cancelled */ const makeWorker = async (workerId, daemonWorkerFacet, cancelled) => { @@ -525,7 +543,7 @@ export const makeDaemonicControlPowers = ( const workerTerminated = Promise.race([workerClosed, capTpClosed]); - /** @type {import('@endo/eventual-send').ERef} */ + /** @type {ERef} */ const workerDaemonFacet = getBootstrap(); return { workerTerminated, workerDaemonFacet }; @@ -538,13 +556,13 @@ export const makeDaemonicControlPowers = ( /** * @param {object} opts - * @param {import('./types.js').Config} opts.config + * @param {Config} opts.config * @param {typeof import('fs')} opts.fs * @param {typeof import('child_process')} opts.popen * @param {typeof import('url')} opts.url - * @param {import('./types.js').FilePowers} opts.filePowers - * @param {import('./types.js').CryptoPowers} opts.cryptoPowers - * @returns {import('./types.js').DaemonicPowers} + * @param {FilePowers} opts.filePowers + * @param {CryptoPowers} opts.cryptoPowers + * @returns {DaemonicPowers} */ export const makeDaemonicPowers = ({ config, diff --git a/packages/daemon/src/daemon-node.js b/packages/daemon/src/daemon-node.js index b7536b66b3..4c84c5502e 100644 --- a/packages/daemon/src/daemon-node.js +++ b/packages/daemon/src/daemon-node.js @@ -23,6 +23,9 @@ import { makeCryptoPowers, } from './daemon-node-powers.js'; +/** @import { PromiseKit } from '@endo/promise-kit' */ +/** @import { Config, Builtins } from './types.js' */ + if (process.argv.length < 5) { throw new Error( `daemon.js requires arguments [sockPath] [statePath] [ephemeralStatePath] [cachePath], got ${process.argv.join( @@ -34,7 +37,7 @@ if (process.argv.length < 5) { const [sockPath, statePath, ephemeralStatePath, cachePath] = process.argv.slice(2); -/** @type {import('./types.js').Config} */ +/** @type {Config} */ const config = { sockPath, statePath, @@ -70,9 +73,7 @@ const reportErrorToParent = message => { }; const { promise: cancelled, reject: cancel } = - /** @type {import('@endo/promise-kit').PromiseKit} */ ( - makePromiseKit() - ); + /** @type {PromiseKit} */ (makePromiseKit()); const updateRecordedPid = async () => { const pidPath = filePowers.joinPath(ephemeralStatePath, 'endo.pid'); @@ -103,7 +104,7 @@ const main = async () => { cancel, cancelled, { - /** @param {import('./types.js').Builtins} builtins */ + /** @param {Builtins} builtins */ APPS: ({ MAIN, NONE }) => ({ type: /** @type {const} */ ('make-unconfined'), worker: MAIN, diff --git a/packages/daemon/src/daemon.js b/packages/daemon/src/daemon.js index 9af94bb386..25dd396a22 100644 --- a/packages/daemon/src/daemon.js +++ b/packages/daemon/src/daemon.js @@ -22,6 +22,66 @@ import { makeWeakMultimap } from './multimap.js'; import { makeLoopbackNetwork } from './networks/loopback.js'; import { assertValidFormulaType } from './formula-type.js'; +/** @import { ERef, FarRef } from '@endo/eventual-send' */ +/** @import { PromiseKit } from '@endo/promise-kit' */ +/** + * @import { + * Builtins, + * Context, + * Controller, + * DaemonCore, + * DaemonCoreExternal, + * DaemonicPowers, + * DeferredTasks, + * DirectoryFormula, + * EndoBootstrap, + * EndoDirectory, + * EndoFormula, + * EndoGateway, + * EndoGreeter, + * EndoGuest, + * EndoHost, + * EndoInspector, + * EndoNetwork, + * EndoPeer, + * EndoReadable, + * EndoWorker, + * EvalFormula, + * FarContext, + * Formula, + * FormulaMakerTable, + * FormulateResult, + * GuestFormula, + * HandleFormula, + * HostFormula, + * Invitation, + * InvitationDeferredTaskParams, + * InvitationFormula, + * KnownEndoInspectors, + * LookupFormula, + * LoopbackNetworkFormula, + * MakeBundleFormula, + * MakeCapletDeferredTaskParams, + * MakeUnconfinedFormula, + * PeerFormula, + * PeerInfo, + * PetInspectorFormula, + * PetStore, + * PetStoreFormula, + * Provide, + * ReadableBlobFormula, + * Sha512, + * Specials, + * WeakMultimap, + * WorkerDaemonFacet, + * WorkerFormula, + * } from './types.js' + */ + +/** + * @param {number} ms + * @param {Promise} cancelled + */ const delay = async (ms, cancelled) => { // Do not attempt to set up a timer if already cancelled. await Promise.race([cancelled, undefined]); @@ -40,7 +100,7 @@ const delay = async (ms, cancelled) => { * @param {string} type - The formula type. * @param {string} number - The formula number. * @param {Record} record - A mapping from special names to formula values. - * @returns {import('./types.js').EndoInspector} The inspector for the given formula. + * @returns {EndoInspector} The inspector for the given formula. */ const makeInspector = (type, number, record) => makeExo( @@ -62,8 +122,8 @@ const makeInspector = (type, number, record) => ); /** - * @param {import('./types.js').Context} context - The context to make far. - * @returns {import('./types.js').FarContext} The far context. + * @param {Context} context - The context to make far. + * @returns {FarContext} The far context. */ const makeFarContext = context => Far('Context', { @@ -78,7 +138,7 @@ const makeFarContext = context => * * @param {string} path * @param {string} rootNonce - * @param {import('./types.js').Sha512} digester + * @param {Sha512} digester * @returns {string} */ const deriveId = (path, rootNonce, digester) => { @@ -89,12 +149,12 @@ const deriveId = (path, rootNonce, digester) => { }; /** - * @param {import('./types.js').DaemonicPowers} powers + * @param {DaemonicPowers} powers * @param {string} rootEntropy * @param {object} args * @param {(error: Error) => void} args.cancel * @param {number} args.gracePeriodMs - * @param {import('./types.js').Specials} args.specials + * @param {Specials} args.specials * @param {Promise} args.gracePeriodElapsed */ const makeDaemonCore = async ( @@ -110,7 +170,7 @@ const makeDaemonCore = async ( } = powers; const { randomHex512 } = cryptoPowers; const contentStore = persistencePowers.makeContentSha512Store(); - /** @type {WeakMap>} */ + /** @type {WeakMap>} */ const workerDaemonFacets = new WeakMap(); /** * Mutations of the formula graph must be serialized through this queue. @@ -167,7 +227,7 @@ const makeDaemonCore = async ( type: 'worker', }); - /** @type {import('./types.js').Builtins} */ + /** @type {Builtins} */ const builtins = { NONE: leastAuthorityId, MAIN: mainWorkerId, @@ -203,13 +263,13 @@ const makeDaemonCore = async ( /** * Forward look-up, for answering "what is the value of this id". - * @type {Map} + * @type {Map} */ const controllerForId = new Map(); /** * Forward look-up, for answering "what is the formula for this id". - * @type {Map} + * @type {Map} */ const formulaForId = new Map(); @@ -242,14 +302,14 @@ const makeDaemonCore = async ( /** * Reverse look-up, for answering "what is my name for this near or far * reference", and not for "what is my name for this promise". - * @type {import('./types.js').WeakMultimap, string>} + * @type {WeakMultimap, string>} */ const idForRef = makeWeakMultimap(); - /** @type {import('./types.js').WeakMultimap, string>['get']} */ + /** @type {WeakMultimap, string>['get']} */ const getIdForRef = ref => idForRef.get(ref); - /** @type {import('./types.js').Provide} */ + /** @type {Provide} */ const provide = (id, _expectedType) => /** @type {any} */ ( // Behold, unavoidable forward-reference: @@ -294,12 +354,12 @@ const makeDaemonCore = async ( }, }); - /** @type {import('./types.js').EndoGreeter} */ + /** @type {EndoGreeter} */ const localGreeter = Far('Greeter', { /** * @param {string} remoteNodeId - * @param {Promise} remoteGateway - * @param {import('@endo/eventual-send').ERef<(error: Error) => void>} cancelConnection + * @param {Promise} remoteGateway + * @param {ERef<(error: Error) => void>} cancelConnection * @param {Promise} connectionCancelled */ hello: async ( @@ -334,16 +394,14 @@ const makeDaemonCore = async ( /** * @param {string} workerId512 - * @param {import('./types.js').Context} context + * @param {Context} context */ const makeIdentifiedWorker = async (workerId512, context) => { // TODO validate workerId512 const daemonWorkerFacet = makeWorkerBootstrap(workerId512); const { promise: forceCancelled, reject: forceCancel } = - /** @type {import('@endo/promise-kit').PromiseKit} */ ( - makePromiseKit() - ); + /** @type {PromiseKit} */ (makePromiseKit()); const { workerTerminated, workerDaemonFacet } = await controlPowers.makeWorker( @@ -379,7 +437,6 @@ const makeDaemonCore = async ( {}, ); - // @ts-expect-error Evidently not specific enough. workerDaemonFacets.set(worker, workerDaemonFacet); return worker; @@ -390,7 +447,7 @@ const makeDaemonCore = async ( */ const makeReadableBlob = sha512 => { const { text, json, streamBase64 } = contentStore.fetch(sha512); - /** @type {import('./types.js').FarEndoReadable} */ + /** @type {FarRef} */ return Far(`Readable file with SHA-512 ${sha512.slice(0, 8)}...`, { sha512: () => sha512, streamBase64, @@ -404,7 +461,7 @@ const makeDaemonCore = async ( * @param {string} source * @param {Array} codeNames * @param {Array} ids - * @param {import('./types.js').Context} context + * @param {Context} context */ const makeEval = async (workerId, source, codeNames, ids, context) => { context.thisDiesIfThatDies(workerId); @@ -440,7 +497,7 @@ const makeDaemonCore = async ( * * @param {string} hubId * @param {string[]} path - * @param {import('./types.js').Context} context + * @param {Context} context */ const makeLookup = async (hubId, path, context) => { context.thisDiesIfThatDies(hubId); @@ -453,7 +510,7 @@ const makeDaemonCore = async ( * @param {string} workerId * @param {string} powersId * @param {string} specifier - * @param {import('./types.js').Context} context + * @param {Context} context */ const makeUnconfined = async (workerId, powersId, specifier, context) => { context.thisDiesIfThatDies(workerId); @@ -475,7 +532,7 @@ const makeDaemonCore = async ( * @param {string} workerId * @param {string} powersId * @param {string} bundleId - * @param {import('./types.js').Context} context + * @param {Context} context */ const makeBundle = async (workerId, powersId, bundleId, context) => { context.thisDiesIfThatDies(workerId); @@ -494,7 +551,7 @@ const makeDaemonCore = async ( ); }; - /** @type {import('./types.js').FormulaMakerTable} */ + /** @type {FormulaMakerTable} */ const makers = { eval: ({ worker, source, names, values }, context) => makeEval(worker, source, names, values, context), @@ -573,7 +630,7 @@ const makeDaemonCore = async ( return handle; }, endo: async ({ host: hostId, networks: networksId, peers: peersId }) => { - /** @type {import('./types.js').FarEndoBootstrap} */ + /** @type {FarRef} */ const endoBootstrap = Far('Endo private facet', { // TODO for user named ping: async () => 'pong', @@ -612,7 +669,7 @@ const makeDaemonCore = async ( const disallowedFn = async () => { throw new Error('not allowed'); }; - return /** @type {import('@endo/far').FarRef} */ ( + return /** @type {FarRef} */ ( /** @type {unknown} */ ( makeExo( 'EndoGuest', @@ -687,8 +744,8 @@ const makeDaemonCore = async ( /** * @param {string} id * @param {string} formulaNumber - * @param {import('./types.js').Formula} formula - * @param {import('./types.js').Context} context + * @param {Formula} formula + * @param {Context} context */ const evaluateFormula = async (id, formulaNumber, formula, context) => { if (Object.hasOwn(makers, formula.type)) { @@ -702,7 +759,7 @@ const makeDaemonCore = async ( /** * @param {string} id - * @param {import('./types.js').Context} context + * @param {Context} context */ const evaluateFormulaForId = async (id, context) => { const { number: formulaNumber, node: formulaNode } = parseId(id); @@ -719,7 +776,7 @@ const makeDaemonCore = async ( return evaluateFormula(id, formulaNumber, formula, context); }; - /** @type {import('./types.js').DaemonCore['formulate']} */ + /** @type {DaemonCore['formulate']} */ const formulate = async (formulaNumber, formula) => { const id = formatId({ number: formulaNumber, @@ -731,10 +788,9 @@ const makeDaemonCore = async ( // Memoize for lookup. console.log(`Making ${formula.type} ${id}`); - const { promise, resolve } = - /** @type {import('@endo/promise-kit').PromiseKit} */ ( - makePromiseKit() - ); + const { promise, resolve } = /** @type {PromiseKit} */ ( + makePromiseKit() + ); // Behold, recursion: // eslint-disable-next-line no-use-before-define @@ -771,17 +827,16 @@ const makeDaemonCore = async ( }); }; - /** @type {import('./types.js').DaemonCore['provideController']} */ + /** @type {DaemonCore['provideController']} */ const provideController = id => { let controller = controllerForId.get(id); if (controller !== undefined) { return controller; } - const { promise, resolve } = - /** @type {import('@endo/promise-kit').PromiseKit} */ ( - makePromiseKit() - ); + const { promise, resolve } = /** @type {PromiseKit} */ ( + makePromiseKit() + ); // Behold, recursion: // eslint-disable-next-line no-use-before-define @@ -815,7 +870,7 @@ const makeDaemonCore = async ( return peerId; }; - /** @type {import('./types.js').DaemonCore['cancelValue']} */ + /** @type {DaemonCore['cancelValue']} */ const cancelValue = async (id, reason) => { await formulaGraphJobs.enqueue(); const controller = provideController(id); @@ -823,7 +878,7 @@ const makeDaemonCore = async ( return controller.context.cancel(reason); }; - /** @type {import('./types.js').DaemonCore['formulateReadableBlob']} */ + /** @type {DaemonCore['formulateReadableBlob']} */ const formulateReadableBlob = async (readerRef, deferredTasks) => { const { formulaNumber, contentSha512 } = await formulaGraphJobs.enqueue( async () => { @@ -843,13 +898,13 @@ const makeDaemonCore = async ( }, ); - /** @type {import('./types.js').ReadableBlobFormula} */ + /** @type {ReadableBlobFormula} */ const formula = { type: 'readable-blob', content: contentSha512, }; - return /** @type {import('./types.js').FormulateResult} */ ( + return /** @type {FormulateResult>} */ ( formulate(formulaNumber, formula) ); }; @@ -858,7 +913,7 @@ const makeDaemonCore = async ( * @param {string} hostAgentId * @param {string} hostHandleId * @param {string} guestName - * @param {import('./types.js').DeferredTasks} deferredTasks + * @param {DeferredTasks} deferredTasks */ const formulateInvitation = async ( hostAgentId, @@ -878,7 +933,7 @@ const makeDaemonCore = async ( return { invitationNumber }; }); - /** @type {import('./types.js').InvitationFormula} */ + /** @type {InvitationFormula} */ const formula = { type: 'invitation', hostAgent: hostAgentId, @@ -886,7 +941,7 @@ const makeDaemonCore = async ( guestName, }; - return /** @type {import('./types.js').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(identifiers.invitationNumber, formula) ); }; @@ -905,7 +960,7 @@ const makeDaemonCore = async ( * @returns {Promise} */ const formulateNumberedHandle = async (formulaNumber, agentId) => { - /** @type {import('./types.js').HandleFormula} */ + /** @type {HandleFormula} */ const formula = { type: 'handle', agent: agentId, @@ -924,32 +979,32 @@ const makeDaemonCore = async ( * The returned promise is resolved after the formula is persisted. * * @param {string} formulaNumber - The formula number of the pet store to formulate. - * @returns {import('./types.js').FormulateResult} The formulated pet store. + * @returns {FormulateResult} The formulated pet store. */ const formulateNumberedPetStore = async formulaNumber => { - /** @type {import('./types.js').PetStoreFormula} */ + /** @type {PetStoreFormula} */ const formula = { type: 'pet-store', }; - return /** @type {import('./types').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(formulaNumber, formula) ); }; /** - * @type {import('./types.js').DaemonCore['formulateDirectory']} + * @type {DaemonCore['formulateDirectory']} */ const formulateDirectory = async () => { const { id: petStoreId } = await formulateNumberedPetStore( await randomHex512(), ); const formulaNumber = await randomHex512(); - /** @type {import('./types.js').DirectoryFormula} */ + /** @type {DirectoryFormula} */ const formula = { type: 'directory', petStore: petStoreId, }; - return /** @type {import('./types').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(formulaNumber, formula) ); }; @@ -959,21 +1014,21 @@ const makeDaemonCore = async ( * The returned promise is resolved after the formula is persisted. * * @param {string} formulaNumber - The worker formula number. - * @returns {ReturnType} + * @returns {ReturnType} */ const formulateNumberedWorker = formulaNumber => { - /** @type {import('./types.js').WorkerFormula} */ + /** @type {WorkerFormula} */ const formula = { type: 'worker', }; - return /** @type {import('./types').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(formulaNumber, formula) ); }; /** - * @type {import('./types.js').DaemonCore['formulateWorker']} + * @type {DaemonCore['formulateWorker']} */ const formulateWorker = async deferredTasks => { return formulateNumberedWorker( @@ -993,7 +1048,7 @@ const makeDaemonCore = async ( }; /** - * @type {import('./types.js').DaemonCore['formulateHostDependencies']} + * @type {DaemonCore['formulateHostDependencies']} */ const formulateHostDependencies = async specifiedIdentifiers => { const { specifiedWorkerId, ...remainingSpecifiedIdentifiers } = @@ -1027,9 +1082,9 @@ const makeDaemonCore = async ( }); }; - /** @type {import('./types.js').DaemonCore['formulateNumberedHost']} */ + /** @type {DaemonCore['formulateNumberedHost']} */ const formulateNumberedHost = identifiers => { - /** @type {import('./types.js').HostFormula} */ + /** @type {HostFormula} */ const formula = { type: 'host', handle: identifiers.handleId, @@ -1040,12 +1095,12 @@ const makeDaemonCore = async ( networks: identifiers.networksDirectoryId, }; - return /** @type {import('./types').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(identifiers.hostFormulaNumber, formula) ); }; - /** @type {import('./types.js').DaemonCore['formulateHost']} */ + /** @type {DaemonCore['formulateHost']} */ const formulateHost = async ( endoId, networksDirectoryId, @@ -1070,7 +1125,7 @@ const makeDaemonCore = async ( ); }; - /** @type {import('./types.js').DaemonCore['formulateGuestDependencies']} */ + /** @type {DaemonCore['formulateGuestDependencies']} */ const formulateGuestDependencies = async (hostAgentId, hostHandleId) => { const guestFormulaNumber = await randomHex512(); const guestId = formatId({ @@ -1092,9 +1147,9 @@ const makeDaemonCore = async ( }); }; - /** @type {import('./types.js').DaemonCore['formulateNumberedGuest']} */ + /** @type {DaemonCore['formulateNumberedGuest']} */ const formulateNumberedGuest = identifiers => { - /** @type {import('./types.js').GuestFormula} */ + /** @type {GuestFormula} */ const formula = { type: 'guest', handle: identifiers.handleId, @@ -1104,12 +1159,12 @@ const makeDaemonCore = async ( worker: identifiers.workerId, }; - return /** @type {import('./types').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(identifiers.guestFormulaNumber, formula) ); }; - /** @type {import('./types.js').DaemonCore['formulateGuest']} */ + /** @type {DaemonCore['formulateGuest']} */ const formulateGuest = async (hostAgentId, hostHandleId, deferredTasks) => { return formulateNumberedGuest( await formulaGraphJobs.enqueue(async () => { @@ -1144,7 +1199,7 @@ const makeDaemonCore = async ( return workerFormulation.id; }; - /** @type {import('./types.js').DaemonCore['formulateEval']} */ + /** @type {DaemonCore['formulateEval']} */ const formulateEval = async ( nameHubId, source, @@ -1189,7 +1244,7 @@ const makeDaemonCore = async ( return identifiers; }); - /** @type {import('./types.js').EvalFormula} */ + /** @type {EvalFormula} */ const formula = { type: 'eval', worker: workerId, @@ -1197,7 +1252,7 @@ const makeDaemonCore = async ( names: codeNames, values: endowmentIds, }; - return /** @type {import('./types.js').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(evalFormulaNumber, formula) ); }; @@ -1210,17 +1265,17 @@ const makeDaemonCore = async ( * hub to call `lookup` on. A "naming hub" is an objected with a variadic * lookup method. It includes objects such as guests and hosts. * @param {string[]} petNamePath - The pet name path to look up. - * @returns {Promise<{ id: string, value: import('./types').EndoWorker }>} + * @returns {Promise<{ id: string, value: EndoWorker }>} */ const formulateNumberedLookup = (formulaNumber, hubId, petNamePath) => { - /** @type {import('./types.js').LookupFormula} */ + /** @type {LookupFormula} */ const formula = { type: 'lookup', hub: hubId, path: petNamePath, }; - return /** @type {import('./types.js').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(formulaNumber, formula) ); }; @@ -1252,7 +1307,7 @@ const makeDaemonCore = async ( * Helper for `formulateUnconfined` and `formulateBundle`. * @param {string} hostAgentId * @param {string} hostHandleId - * @param {import('./types.js').DeferredTasks} deferredTasks + * @param {DeferredTasks} deferredTasks * @param {string} [specifiedWorkerId] * @param {string} [specifiedPowersId] */ @@ -1281,7 +1336,7 @@ const makeDaemonCore = async ( return identifiers; }; - /** @type {import('./types.js').DaemonCore['formulateUnconfined']} */ + /** @type {DaemonCore['formulateUnconfined']} */ const formulateUnconfined = async ( hostAgentId, hostHandleId, @@ -1301,7 +1356,7 @@ const makeDaemonCore = async ( ), ); - /** @type {import('./types.js').MakeUnconfinedFormula} */ + /** @type {MakeUnconfinedFormula} */ const formula = { type: 'make-unconfined', worker: workerId, @@ -1311,7 +1366,7 @@ const makeDaemonCore = async ( return formulate(capletFormulaNumber, formula); }; - /** @type {import('./types.js').DaemonCore['formulateBundle']} */ + /** @type {DaemonCore['formulateBundle']} */ const formulateBundle = async ( hostAgentId, hostHandleId, @@ -1331,7 +1386,7 @@ const makeDaemonCore = async ( ), ); - /** @type {import('./types.js').MakeBundleFormula} */ + /** @type {MakeBundleFormula} */ const formula = { type: 'make-bundle', worker: workerId, @@ -1346,46 +1401,46 @@ const makeDaemonCore = async ( * @param {string} petStoreId */ const formulateNumberedPetInspector = (formulaNumber, petStoreId) => { - /** @type {import('./types.js').PetInspectorFormula} */ + /** @type {PetInspectorFormula} */ const formula = { type: 'pet-inspector', petStore: petStoreId, }; - return /** @type {import('./types').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(formulaNumber, formula) ); }; - /** @type {import('./types.js').DaemonCore['formulatePeer']} */ + /** @type {DaemonCore['formulatePeer']} */ const formulatePeer = async (networksDirectoryId, nodeId, addresses) => { const formulaNumber = await randomHex512(); // TODO: validate addresses // TODO: mutable state like addresses should not be stored in formula - /** @type {import('./types.js').PeerFormula} */ + /** @type {PeerFormula} */ const formula = { type: 'peer', networks: networksDirectoryId, node: nodeId, addresses, }; - return /** @type {import('./types').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(formulaNumber, formula) ); }; - /** @type {import('./types.js').DaemonCore['formulateLoopbackNetwork']} */ + /** @type {DaemonCore['formulateLoopbackNetwork']} */ const formulateLoopbackNetwork = async () => { const formulaNumber = await randomHex512(); - /** @type {import('./types').LoopbackNetworkFormula} */ + /** @type {LoopbackNetworkFormula} */ const formula = { type: 'loopback-network', }; - return /** @type {import('./types').FormulateResult} */ ( + return /** @type {FormulateResult} */ ( formulate(formulaNumber, formula) ); }; - /** @type {import('./types.js').DaemonCore['formulateNetworksDirectory']} */ + /** @type {DaemonCore['formulateNetworksDirectory']} */ const formulateNetworksDirectory = async () => { const { id, value } = await formulateDirectory(); // Make default networks. @@ -1394,7 +1449,7 @@ const makeDaemonCore = async ( return { id, value }; }; - /** @type {import('./types.js').DaemonCore['formulateEndoBootstrap']} */ + /** @type {DaemonCore['formulateEndoBootstrap']} */ const formulateEndoBootstrap = async specifiedFormulaNumber => { const identifiers = await formulaGraphJobs.enqueue(async () => { const formulaNumber = await (specifiedFormulaNumber ?? randomHex512()); @@ -1424,7 +1479,7 @@ const makeDaemonCore = async ( }; }); - /** @type {import('./types.js').EndoFormula} */ + /** @type {EndoFormula} */ const formula = { type: 'endo', networks: identifiers.networksDirectoryId, @@ -1433,14 +1488,14 @@ const makeDaemonCore = async ( leastAuthority: leastAuthorityId, }; - return /** @type {import('./types').FormulateResult} */ ( + return /** @type {FormulateResult>} */ ( formulate(identifiers.formulaNumber, formula) ); }; /** * @param {string} networksDirectoryId - * @returns {Promise} + * @returns {Promise} */ const getAllNetworks = async networksDirectoryId => { const networksDirectory = await provide(networksDirectoryId, 'directory'); @@ -1451,7 +1506,7 @@ const makeDaemonCore = async ( return networks; }; - /** @type {import('./types.js').DaemonCore['getAllNetworkAddresses']} */ + /** @type {DaemonCore['getAllNetworkAddresses']} */ const getAllNetworkAddresses = async networksDirectoryId => { const networks = await getAllNetworks(networksDirectoryId); const addresses = ( @@ -1468,7 +1523,7 @@ const makeDaemonCore = async ( * @param {string} networksDirectoryId * @param {string} nodeId * @param {string[]} addresses - * @param {import('./types.js').Context} context + * @param {Context} context */ const makePeer = async (networksDirectoryId, nodeId, addresses, context) => { const remoteControl = provideRemoteControl(nodeId); @@ -1504,9 +1559,7 @@ const makeDaemonCore = async ( * @param {string} guestName */ const makeInvitation = async (id, hostAgentId, hostHandleId, guestName) => { - const hostAgent = /** @type {import('./types.js').EndoHost} */ ( - await provide(hostAgentId) - ); + const hostAgent = /** @type {EndoHost} */ (await provide(hostAgentId)); const locate = async () => { const { node, addresses } = await hostAgent.getPeerInfo(); @@ -1540,7 +1593,7 @@ const makeDaemonCore = async ( number: guestHandleNumber, }); - /** @type {import('./types.js').PeerInfo} */ + /** @type {PeerInfo} */ const peerInfo = { node: guestNodeNumber, addresses, @@ -1612,14 +1665,14 @@ const makeDaemonCore = async ( * more details. * * @param {string} petStoreId - * @returns {Promise} + * @returns {Promise} */ const makePetStoreInspector = async petStoreId => { const petStore = await provide(petStoreId, 'pet-store'); /** * @param {string} petName - The pet name to inspect. - * @returns {Promise} An + * @returns {Promise} An * inspector for the value of the given pet name. */ const lookup = async petName => { @@ -1716,7 +1769,7 @@ const makeDaemonCore = async ( return info; }; - /** @type {import('./types.js').DaemonCoreExternal} */ + /** @type {DaemonCoreExternal} */ return { formulateEndoBootstrap, provide, @@ -1725,13 +1778,13 @@ const makeDaemonCore = async ( }; /** - * @param {import('./types.js').DaemonicPowers} powers + * @param {DaemonicPowers} powers * @param {object} args * @param {(error: Error) => void} args.cancel * @param {number} args.gracePeriodMs * @param {Promise} args.gracePeriodElapsed - * @param {import('./types.js').Specials} args.specials - * @returns {Promise} + * @param {Specials} args.specials + * @returns {Promise>} */ const provideEndoBootstrap = async ( powers, @@ -1752,7 +1805,7 @@ const provideEndoBootstrap = async ( number: endoFormulaNumber, node: daemonCore.nodeId, }); - return /** @type {Promise} */ ( + return /** @type {Promise>} */ ( daemonCore.provide(endoId) ); } else { @@ -1764,11 +1817,11 @@ const provideEndoBootstrap = async ( }; /** - * @param {import('./types.js').DaemonicPowers} powers + * @param {DaemonicPowers} powers * @param {string} daemonLabel * @param {(error: Error) => void} cancel * @param {Promise} cancelled - * @param {import('./types.js').Specials} [specials] + * @param {Specials} [specials] */ export const makeDaemon = async ( powers, @@ -1778,9 +1831,7 @@ export const makeDaemon = async ( specials = {}, ) => { const { promise: gracePeriodCancelled, reject: cancelGracePeriod } = - /** @type {import('@endo/promise-kit').PromiseKit} */ ( - makePromiseKit() - ); + /** @type {PromiseKit} */ (makePromiseKit()); // TODO thread through command arguments. const gracePeriodMs = 100; diff --git a/packages/daemon/src/deferred-tasks.js b/packages/daemon/src/deferred-tasks.js index a815dcbd9e..d7b1b8385b 100644 --- a/packages/daemon/src/deferred-tasks.js +++ b/packages/daemon/src/deferred-tasks.js @@ -1,8 +1,13 @@ +// @ts-check + +/** @import { DeferredTasks, DeferredTask } from './types.js' */ + /** - * @returns {import('./types.js').DeferredTasks} + * @template {Record} T + * @returns {DeferredTasks} */ export const makeDeferredTasks = () => { - /** @type {import('./types.js').DeferredTask[]} */ + /** @type {DeferredTask[]} */ const tasks = []; return { diff --git a/packages/daemon/src/directory.js b/packages/daemon/src/directory.js index 584eae059e..3c2abe3d12 100644 --- a/packages/daemon/src/directory.js +++ b/packages/daemon/src/directory.js @@ -8,12 +8,23 @@ import { formatLocator, idFromLocator } from './locator.js'; const { quote: q } = assert; +/** + * @import { + * DaemonCore, + * MakeDirectoryNode, + * EndoDirectory, + * NameHub, + * LocatorNameChange, + * Context, + * } from './types.js' + */ + /** * @param {object} args - * @param {import('./types.js').DaemonCore['provide']} args.provide - * @param {import('./types.js').DaemonCore['getIdForRef']} args.getIdForRef - * @param {import('./types.js').DaemonCore['getTypeForId']} args.getTypeForId - * @param {import('./types.js').DaemonCore['formulateDirectory']} args.formulateDirectory + * @param {DaemonCore['provide']} args.provide + * @param {DaemonCore['getIdForRef']} args.getIdForRef + * @param {DaemonCore['getTypeForId']} args.getTypeForId + * @param {DaemonCore['formulateDirectory']} args.formulateDirectory */ export const makeDirectoryMaker = ({ provide, @@ -21,9 +32,9 @@ export const makeDirectoryMaker = ({ getTypeForId, formulateDirectory, }) => { - /** @type {import('./types.js').MakeDirectoryNode} */ + /** @type {MakeDirectoryNode} */ const makeDirectoryNode = petStore => { - /** @type {import('./types.js').EndoDirectory['lookup']} */ + /** @type {EndoDirectory['lookup']} */ const lookup = (...petNamePath) => { const [headName, ...tailNames] = petNamePath; const id = petStore.identifyLocal(headName); @@ -37,7 +48,7 @@ export const makeDirectoryMaker = ({ ); }; - /** @type {import('./types.js').EndoDirectory['reverseLookup']} */ + /** @type {EndoDirectory['reverseLookup']} */ const reverseLookup = async presence => { const id = getIdForRef(await presence); if (id === undefined) { @@ -48,7 +59,7 @@ export const makeDirectoryMaker = ({ /** * @param {Array} petNamePath - * @returns {Promise<{ hub: import('./types.js').NameHub, name: string }>} + * @returns {Promise<{ hub: NameHub, name: string }>} */ const lookupTailNameHub = async petNamePath => { if (petNamePath.length === 0) { @@ -60,13 +71,11 @@ export const makeDirectoryMaker = ({ // eslint-disable-next-line no-use-before-define return { hub: directory, name: tailName }; } - const nameHub = /** @type {import('./types.js').NameHub} */ ( - await lookup(...headPath) - ); + const nameHub = /** @type {NameHub} */ (await lookup(...headPath)); return { hub: nameHub, name: tailName }; }; - /** @type {import('./types.js').EndoDirectory['has']} */ + /** @type {EndoDirectory['has']} */ const has = async (...petNamePath) => { if (petNamePath.length === 1) { const petName = petNamePath[0]; @@ -76,7 +85,7 @@ export const makeDirectoryMaker = ({ return hub.has(name); }; - /** @type {import('./types.js').EndoDirectory['identify']} */ + /** @type {EndoDirectory['identify']} */ const identify = async (...petNamePath) => { if (petNamePath.length === 1) { const petName = petNamePath[0]; @@ -86,7 +95,7 @@ export const makeDirectoryMaker = ({ return hub.identify(name); }; - /** @type {import('./types.js').EndoDirectory['locate']} */ + /** @type {EndoDirectory['locate']} */ const locate = async (...petNamePath) => { const id = await identify(...petNamePath); if (id === undefined) { @@ -97,13 +106,13 @@ export const makeDirectoryMaker = ({ return formatLocator(id, formulaType); }; - /** @type {import('./types.js').EndoDirectory['reverseLocate']} */ + /** @type {EndoDirectory['reverseLocate']} */ const reverseLocate = async locator => { const id = idFromLocator(locator); return petStore.reverseIdentify(id); }; - /** @type {import('./types.js').EndoDirectory['followLocatorNameChanges']} */ + /** @type {EndoDirectory['followLocatorNameChanges']} */ const followLocatorNameChanges = async function* followLocatorNameChanges( locator, ) { @@ -117,22 +126,20 @@ export const makeDirectoryMaker = ({ : { remove: locator }), }; - yield /** @type {import('./types.js').LocatorNameChange} */ locatorNameChange; + yield /** @type {LocatorNameChange} */ (locatorNameChange); } }; - /** @type {import('./types.js').EndoDirectory['list']} */ + /** @type {EndoDirectory['list']} */ const list = async (...petNamePath) => { if (petNamePath.length === 0) { return petStore.list(); } - const hub = /** @type {import('./types.js').NameHub} */ ( - await lookup(...petNamePath) - ); + const hub = /** @type {NameHub} */ (await lookup(...petNamePath)); return hub.list(); }; - /** @type {import('./types.js').EndoDirectory['listIdentifiers']} */ + /** @type {EndoDirectory['listIdentifiers']} */ const listIdentifiers = async (...petNamePath) => { const names = await list(...petNamePath); const identities = new Set(); @@ -147,7 +154,7 @@ export const makeDirectoryMaker = ({ return harden(Array.from(identities).sort()); }; - /** @type {import('./types.js').EndoDirectory['followNameChanges']} */ + /** @type {EndoDirectory['followNameChanges']} */ const followNameChanges = async function* followNameChanges( ...petNamePath ) { @@ -155,13 +162,11 @@ export const makeDirectoryMaker = ({ yield* petStore.followNameChanges(); return; } - const hub = /** @type {import('./types.js').NameHub} */ ( - await lookup(...petNamePath) - ); + const hub = /** @type {NameHub} */ (await lookup(...petNamePath)); yield* hub.followNameChanges(); }; - /** @type {import('./types.js').EndoDirectory['remove']} */ + /** @type {EndoDirectory['remove']} */ const remove = async (...petNamePath) => { if (petNamePath.length === 1) { const petName = petNamePath[0]; @@ -172,7 +177,7 @@ export const makeDirectoryMaker = ({ await hub.remove(name); }; - /** @type {import('./types.js').EndoDirectory['move']} */ + /** @type {EndoDirectory['move']} */ const move = async (fromPath, toPath) => { const { hub: fromHub, name: fromName } = await lookupTailNameHub( fromPath, @@ -196,7 +201,7 @@ export const makeDirectoryMaker = ({ await Promise.all([addP, removeP]); }; - /** @type {import('./types.js').EndoDirectory['copy']} */ + /** @type {EndoDirectory['copy']} */ const copy = async (fromPath, toPath) => { const { hub: fromHub, name: fromName } = await lookupTailNameHub( fromPath, @@ -209,14 +214,14 @@ export const makeDirectoryMaker = ({ await toHub.write([toName], id); }; - /** @type {import('./types.js').EndoDirectory['makeDirectory']} */ + /** @type {EndoDirectory['makeDirectory']} */ const makeDirectory = async directoryPetName => { const { value: directory, id } = await formulateDirectory(); await petStore.write(directoryPetName, id); return directory; }; - /** @type {import('./types.js').EndoDirectory['write']} */ + /** @type {EndoDirectory['write']} */ const write = async (petNamePath, id) => { if (petNamePath.length === 1) { const petName = petNamePath[0]; @@ -227,7 +232,7 @@ export const makeDirectoryMaker = ({ await hub.write([name], id); }; - /** @type {import('./types.js').EndoDirectory} */ + /** @type {EndoDirectory} */ const directory = { has, identify, @@ -251,7 +256,7 @@ export const makeDirectoryMaker = ({ /** * @param {object} args * @param {string} args.petStoreId - * @param {import('./types.js').Context} args.context + * @param {Context} args.context */ const makeIdentifiedDirectory = async ({ petStoreId, context }) => { // TODO thread context diff --git a/packages/daemon/src/formula-identifier.js b/packages/daemon/src/formula-identifier.js index 4ee33bf01e..165e5dc1ce 100644 --- a/packages/daemon/src/formula-identifier.js +++ b/packages/daemon/src/formula-identifier.js @@ -1,5 +1,8 @@ +// @ts-check /// +/** @import { IdRecord } from './types.js' */ + const { quote: q } = assert; const numberPattern = /^[0-9a-f]{128}$/; @@ -37,7 +40,7 @@ export const assertValidId = (id, petName) => { /** * @param {string} id - * @returns {import("./types").IdRecord} + * @returns {IdRecord} */ export const parseId = id => { const match = idPattern.exec(id); @@ -58,7 +61,7 @@ export const parseId = id => { }; /** - * @param {import("./types").IdRecord} formulaRecord + * @param {IdRecord} formulaRecord * @returns {string} */ export const formatId = ({ number, node }) => { diff --git a/packages/daemon/src/guest.js b/packages/daemon/src/guest.js index e672d7c0b7..167a5ae925 100644 --- a/packages/daemon/src/guest.js +++ b/packages/daemon/src/guest.js @@ -5,11 +5,21 @@ import { M } from '@endo/patterns'; import { makeIteratorRef } from './reader-ref.js'; import { makePetSitter } from './pet-sitter.js'; +/** + * @import { + * Context, + * EndoGuest, + * MakeDirectoryNode, + * MakeMailbox, + * Provide, + * } from './types.js' + */ + /** * @param {object} args - * @param {import('./types.js').DaemonCore['provide']} args.provide - * @param {import('./types.js').MakeMailbox} args.makeMailbox - * @param {import('./types.js').MakeDirectoryNode} args.makeDirectoryNode + * @param {Provide} args.provide + * @param {MakeMailbox} args.makeMailbox + * @param {MakeDirectoryNode} args.makeDirectoryNode */ export const makeGuestMaker = ({ provide, makeMailbox, makeDirectoryNode }) => { /** @@ -19,7 +29,7 @@ export const makeGuestMaker = ({ provide, makeMailbox, makeDirectoryNode }) => { * @param {string} hostHandleId * @param {string} petStoreId * @param {string} mainWorkerId - * @param {import('./types.js').Context} context + * @param {Context} context */ const makeGuest = async ( guestId, @@ -80,7 +90,7 @@ export const makeGuestMaker = ({ provide, makeMailbox, makeDirectoryNode }) => { deliver, } = mailbox; - /** @type {import('./types.js').EndoGuest} */ + /** @type {EndoGuest} */ const guest = { // Directory has, diff --git a/packages/daemon/src/host.js b/packages/daemon/src/host.js index 5308c8cdb6..fd1bfa0c1b 100644 --- a/packages/daemon/src/host.js +++ b/packages/daemon/src/host.js @@ -1,6 +1,27 @@ // @ts-check /// +/** @import { ERef } from '@endo/eventual-send' */ +/** + * @import { + * AgentDeferredTaskParams, + * Context, + * DaemonCore, + * DeferredTasks, + * EndoGuest, + * EndoHost, + * EvalDeferredTaskParams, + * InvitationDeferredTaskParams, + * MakeCapletDeferredTaskParams, + * MakeDirectoryNode, + * MakeHostOrGuestOptions, + * MakeMailbox, + * PeerInfo, + * ReadableBlobDeferredTaskParams, + * WorkerDeferredTaskParams, + * } from './types.js' + */ + import { E } from '@endo/far'; import { makeExo } from '@endo/exo'; import { M } from '@endo/patterns'; @@ -19,20 +40,20 @@ const assertPowersName = name => { /** * @param {object} args - * @param {import('./types.js').DaemonCore['provide']} args.provide - * @param {import('./types.js').DaemonCore['provideController']} args.provideController - * @param {import('./types.js').DaemonCore['cancelValue']} args.cancelValue - * @param {import('./types.js').DaemonCore['formulateWorker']} args.formulateWorker - * @param {import('./types.js').DaemonCore['formulateHost']} args.formulateHost - * @param {import('./types.js').DaemonCore['formulateGuest']} args.formulateGuest - * @param {import('./types.js').DaemonCore['formulateEval']} args.formulateEval - * @param {import('./types.js').DaemonCore['formulateUnconfined']} args.formulateUnconfined - * @param {import('./types.js').DaemonCore['formulateBundle']} args.formulateBundle - * @param {import('./types.js').DaemonCore['formulateReadableBlob']} args.formulateReadableBlob - * @param {import('./types.js').DaemonCore['formulateInvitation']} args.formulateInvitation - * @param {import('./types.js').DaemonCore['getAllNetworkAddresses']} args.getAllNetworkAddresses - * @param {import('./types.js').MakeMailbox} args.makeMailbox - * @param {import('./types.js').MakeDirectoryNode} args.makeDirectoryNode + * @param {DaemonCore['provide']} args.provide + * @param {DaemonCore['provideController']} args.provideController + * @param {DaemonCore['cancelValue']} args.cancelValue + * @param {DaemonCore['formulateWorker']} args.formulateWorker + * @param {DaemonCore['formulateHost']} args.formulateHost + * @param {DaemonCore['formulateGuest']} args.formulateGuest + * @param {DaemonCore['formulateEval']} args.formulateEval + * @param {DaemonCore['formulateUnconfined']} args.formulateUnconfined + * @param {DaemonCore['formulateBundle']} args.formulateBundle + * @param {DaemonCore['formulateReadableBlob']} args.formulateReadableBlob + * @param {DaemonCore['formulateInvitation']} args.formulateInvitation + * @param {DaemonCore['getAllNetworkAddresses']} args.getAllNetworkAddresses + * @param {MakeMailbox} args.makeMailbox + * @param {MakeDirectoryNode} args.makeDirectoryNode * @param {string} args.localNodeId */ export const makeHostMaker = ({ @@ -62,7 +83,7 @@ export const makeHostMaker = ({ * @param {string} networksDirectoryId * @param {string} leastAuthorityId * @param {{[name: string]: string}} platformNames - * @param {import('./types.js').Context} context + * @param {Context} context */ const makeHost = async ( hostId, @@ -101,11 +122,11 @@ export const makeHostMaker = ({ const getEndoBootstrap = async () => provide(endoId, 'endo'); /** - * @param {import('@endo/eventual-send').ERef>} readerRef + * @param {ERef>} readerRef * @param {string} [petName] */ const store = async (readerRef, petName) => { - /** @type {import('./types.js').DeferredTasks} */ + /** @type {DeferredTasks} */ const tasks = makeDeferredTasks(); if (petName !== undefined) { @@ -123,7 +144,7 @@ export const makeHostMaker = ({ * @param {string} workerName */ const provideWorker = async workerName => { - /** @type {import('./types.js').DeferredTasks} */ + /** @type {DeferredTasks} */ const tasks = makeDeferredTasks(); // eslint-disable-next-line no-use-before-define const workerId = prepareWorkerFormulation(workerName, tasks.push); @@ -138,7 +159,7 @@ export const makeHostMaker = ({ /** * @param {string} workerName - * @param {import('./types.js').DeferredTasks<{ workerId: string }>['push']} deferTask + * @param {DeferredTasks<{ workerId: string }>['push']} deferTask */ const prepareWorkerFormulation = (workerName, deferTask) => { if (workerName === 'MAIN') { @@ -177,7 +198,7 @@ export const makeHostMaker = ({ throw new Error('Evaluator requires one pet name for each code name'); } - /** @type {import('./types.js').DeferredTasks} */ + /** @type {DeferredTasks} */ const tasks = makeDeferredTasks(); const workerId = prepareWorkerFormulation(workerName, tasks.push); @@ -228,7 +249,7 @@ export const makeHostMaker = ({ const prepareMakeCaplet = (powersName, workerName, resultName) => { assertPowersName(powersName); - /** @type {import('./types.js').DeferredTasks} */ + /** @type {DeferredTasks} */ const tasks = makeDeferredTasks(); const workerId = prepareWorkerFormulation(workerName, tasks.push); @@ -249,7 +270,7 @@ export const makeHostMaker = ({ return { tasks, workerId, powersId }; }; - /** @type {import('./types.js').EndoHost['makeUnconfined']} */ + /** @type {EndoHost['makeUnconfined']} */ const makeUnconfined = async ( workerName, specifier, @@ -355,7 +376,7 @@ export const makeHostMaker = ({ * @param {string} [agentName] - The pet name of the agent. */ const getDeferredTasksForAgent = (handleName, agentName) => { - /** @type {import('./types.js').DeferredTasks} */ + /** @type {DeferredTasks} */ const tasks = makeDeferredTasks(); if (handleName !== undefined) { tasks.push(identifiers => @@ -372,8 +393,8 @@ export const makeHostMaker = ({ /** * @param {string} [petName] - * @param {import('./types.js').MakeHostOrGuestOptions} [opts] - * @returns {Promise<{id: string, value: Promise}>} + * @param {MakeHostOrGuestOptions} [opts] + * @returns {Promise<{id: string, value: Promise}>} */ const makeChildHost = async ( petName, @@ -393,11 +414,11 @@ export const makeHostMaker = ({ await introduceNamesToAgent(host.id, introducedNames); - /** @type {{ id: string, value: Promise }} */ + /** @type {{ id: string, value: Promise }} */ return host; }; - /** @type {import('./types.js').EndoHost['provideHost']} */ + /** @type {EndoHost['provideHost']} */ const provideHost = async (petName, opts) => { const { value } = await makeChildHost(petName, opts); return value; @@ -405,8 +426,8 @@ export const makeHostMaker = ({ /** * @param {string} [handleName] - * @param {import('./types.js').MakeHostOrGuestOptions} [opts] - * @returns {Promise<{id: string, value: Promise}>} + * @param {MakeHostOrGuestOptions} [opts] + * @returns {Promise<{id: string, value: Promise}>} */ const makeGuest = async ( handleName, @@ -426,11 +447,11 @@ export const makeHostMaker = ({ await introduceNamesToAgent(guest.id, introducedNames); - /** @type {{ id: string, value: Promise }} */ + /** @type {{ id: string, value: Promise }} */ return guest; }; - /** @type {import('./types.js').EndoHost['provideGuest']} */ + /** @type {EndoHost['provideGuest']} */ const provideGuest = async (petName, opts) => { const { value } = await makeGuest(petName, opts); return value; @@ -448,7 +469,7 @@ export const makeHostMaker = ({ // Overwriting the guestName must cancel the pending invitation (consume // once) so that the invitation can no longer modify the petStore entry // for the guestName. - /** @type {import('./types.js').DeferredTasks} */ + /** @type {DeferredTasks} */ const tasks = makeDeferredTasks(); tasks.push(identifiers => petStore.write(guestName, identifiers.invitationId), @@ -481,7 +502,7 @@ export const makeHostMaker = ({ throw assert.error(`Invitation must have an "id" parameter`); } - /** @type {import('./types.js').PeerInfo} */ + /** @type {PeerInfo} */ const peerInfo = { node: nodeNumber, addresses, @@ -514,7 +535,7 @@ export const makeHostMaker = ({ await petStore.write(guestName, guestHandleId); }; - /** @type {import('./types.js').EndoHost['cancel']} */ + /** @type {EndoHost['cancel']} */ const cancel = async (petName, reason = new Error('Cancelled')) => { const id = petStore.identifyLocal(petName); if (id === undefined) { @@ -523,25 +544,25 @@ export const makeHostMaker = ({ return cancelValue(id, reason); }; - /** @type {import('./types.js').EndoHost['gateway']} */ + /** @type {EndoHost['gateway']} */ const gateway = async () => { const endoBootstrap = getEndoBootstrap(); return E(endoBootstrap).gateway(); }; - /** @type {import('./types.js').EndoHost['greeter']} */ + /** @type {EndoHost['greeter']} */ const greeter = async () => { const endoBootstrap = getEndoBootstrap(); return E(endoBootstrap).greeter(); }; - /** @type {import('./types.js').EndoHost['addPeerInfo']} */ + /** @type {EndoHost['addPeerInfo']} */ const addPeerInfo = async peerInfo => { const endoBootstrap = getEndoBootstrap(); await E(endoBootstrap).addPeerInfo(peerInfo); }; - /** @type {import('./types.js').EndoHost['getPeerInfo']} */ + /** @type {EndoHost['getPeerInfo']} */ const getPeerInfo = async () => { const addresses = await getAllNetworkAddresses(networksDirectoryId); const peerInfo = { @@ -581,7 +602,7 @@ export const makeHostMaker = ({ deliver, } = mailbox; - /** @type {import('./types.js').EndoHost} */ + /** @type {EndoHost} */ const host = { // Directory has, diff --git a/packages/daemon/src/mail.js b/packages/daemon/src/mail.js index a4a15de365..455bf719e6 100644 --- a/packages/daemon/src/mail.js +++ b/packages/daemon/src/mail.js @@ -7,6 +7,22 @@ import { makePromiseKit } from '@endo/promise-kit'; import { makeChangeTopic } from './pubsub.js'; import { assertPetName } from './pet-name.js'; +/** @import { ERef } from '@endo/eventual-send' */ +/** @import { PromiseKit } from '@endo/promise-kit' */ +/** + * @import { + * Envelope, + * EnvelopedMessage, + * Handle, + * Mail, + * MakeMailbox, + * Provide, + * Request, + * StampedMessage, + * Topic, + * } from './types.js' + */ + const { quote: q } = assert; /** @@ -15,7 +31,7 @@ const { quote: q } = assert; * @param {string} toId */ const makeRequest = (description, fromId, toId) => { - /** @type {import('@endo/promise-kit/src/types.js').PromiseKit} */ + /** @type {PromiseKit} */ const { promise, resolve } = makePromiseKit(); const settled = promise.then( () => /** @type {const} */ ('fulfilled'), @@ -50,27 +66,27 @@ const makeEnvelope = () => makeExo('Envelope', EnvelopeShape, {}); /** * @param {object} args - * @param {import('./types.js').DaemonCore['provide']} args.provide - * @returns {import('./types.js').MakeMailbox} + * @param {Provide} args.provide + * @returns {MakeMailbox} */ export const makeMailboxMaker = ({ provide }) => { /** - @type {import('./types.js').MakeMailbox} */ + @type {MakeMailbox} */ const makeMailbox = ({ selfId, petStore, context }) => { - /** @type {Map} */ + /** @type {Map} */ const messages = new Map(); - /** @type {WeakMap<{}, import('./types.js').EnvelopedMessage>} */ + /** @type {WeakMap<{}, EnvelopedMessage>} */ const outbox = new WeakMap(); - /** @type {import('./types.js').Topic} */ + /** @type {Topic} */ const messagesTopic = makeChangeTopic(); let nextMessageNumber = 0; - /** @type {import('./types.js').Mail['listMessages']} */ + /** @type {Mail['listMessages']} */ const listMessages = async () => harden(Array.from(messages.values())); - /** @type {import('./types.js').Mail['followMessages']} */ + /** @type {Mail['followMessages']} */ const followMessages = async function* currentAndSubsequentMessages() { const subsequentRequests = messagesTopic.subscribe(); yield* messages.values(); @@ -78,10 +94,10 @@ export const makeMailboxMaker = ({ provide }) => { }; /** - * @param {import('./types.js').EnvelopedMessage} envelope + * @param {EnvelopedMessage} envelope */ const deliver = envelope => { - /** @type {import('@endo/promise-kit/src/types.js').PromiseKit} */ + /** @type {PromiseKit} */ const dismissal = makePromiseKit(); const messageNumber = nextMessageNumber; nextMessageNumber += 1; @@ -116,8 +132,8 @@ export const makeMailboxMaker = ({ provide }) => { }; /** - * @param {import('./types.js').Handle} recipient - * @param {import('./types.js').EnvelopedMessage} message + * @param {Handle} recipient + * @param {EnvelopedMessage} message */ const post = async (recipient, message) => { /** @param {object} allegedRecipient */ @@ -130,7 +146,7 @@ export const makeMailboxMaker = ({ provide }) => { } }; - /** @type {import('./types.js').Mail['resolve']} */ + /** @type {Mail['resolve']} */ const resolve = async (messageNumber, resolutionName) => { assertPetName(resolutionName); if ( @@ -150,18 +166,18 @@ export const makeMailboxMaker = ({ provide }) => { ); } // TODO validate shape of request - const req = /** @type {import('./types.js').Request} */ (message); + const req = /** @type {Request} */ (message); const { responder } = E.get(req); E.sendOnly(responder).respondId(id); }; // TODO test reject - /** @type {import('./types.js').Mail['reject']} */ + /** @type {Mail['reject']} */ const reject = async (messageNumber, reason = 'Declined') => { const message = messages.get(messageNumber); if (message !== undefined) { // TODO verify that the message is a request. - const req = /** @type {import('./types.js').Request} */ (message); + const req = /** @type {Request} */ (message); const { responder } = E.get(req); E.sendOnly(responder).respondId( harden(Promise.reject(harden(new Error(reason)))), @@ -169,15 +185,13 @@ export const makeMailboxMaker = ({ provide }) => { } }; - /** @type {import('./types.js').Mail['send']} */ + /** @type {Mail['send']} */ const send = async (toName, strings, edgeNames, petNames) => { const toId = petStore.identifyLocal(toName); if (toId === undefined) { throw new Error(`Unknown recipient ${toName}`); } - const to = /** @type {import('./types.js').Handle} */ ( - await provide(toId) - ); + const to = /** @type {Handle} */ (await provide(toId)); petNames.forEach(assertPetName); edgeNames.forEach(assertPetName); @@ -215,7 +229,7 @@ export const makeMailboxMaker = ({ provide }) => { await post(to, message); }; - /** @type {import('./types.js').Mail['dismiss']} */ + /** @type {Mail['dismiss']} */ const dismiss = async messageNumber => { if ( typeof messageNumber !== 'number' || @@ -231,7 +245,7 @@ export const makeMailboxMaker = ({ provide }) => { return E(dismisser).dismiss(); }; - /** @type {import('./types.js').Mail['adopt']} */ + /** @type {Mail['adopt']} */ const adopt = async (messageNumber, edgeName, petName) => { assertPetName(edgeName); assertPetName(petName); @@ -266,7 +280,7 @@ export const makeMailboxMaker = ({ provide }) => { await petStore.write(petName, id); }; - /** @type {import('./types.js').Mail['request']} */ + /** @type {Mail['request']} */ const request = async (toName, description, responseName) => { if (responseName !== undefined) { const responseId = petStore.identifyLocal(responseName); @@ -279,9 +293,7 @@ export const makeMailboxMaker = ({ provide }) => { if (toId === undefined) { throw new Error(`Unknown recipient ${toName}`); } - const to = /** @type {import('./types.js').Handle} */ ( - await provide(toId) - ); + const to = /** @type {Handle} */ (await provide(toId)); const { request: req, response: responseIdP } = makeRequest( description, @@ -303,7 +315,7 @@ export const makeMailboxMaker = ({ provide }) => { }; /** - * @param {import('./types.js').Envelope} envelope + * @param {Envelope} envelope */ const open = envelope => { const message = outbox.get(envelope); @@ -316,13 +328,11 @@ export const makeMailboxMaker = ({ provide }) => { // When receiving an envelope, we can assume we are the intended recipient // but we cannot assume the alleged sender. /** - * @param {import('@endo/eventual-send').ERef} envelope + * @param {ERef} envelope * @param {string} allegedFromId */ const receive = async (envelope, allegedFromId) => { - const sender = /** @type {Promise} */ ( - provide(allegedFromId) - ); + const sender = /** @type {Promise} */ (provide(allegedFromId)); const message = await E(sender).open(envelope); if (allegedFromId !== message.from) { throw new Error('Mail fraud: alleged sender does not recognize parcel'); diff --git a/packages/daemon/src/multimap.js b/packages/daemon/src/multimap.js index f4e84b9b49..7d91e3ed8e 100644 --- a/packages/daemon/src/multimap.js +++ b/packages/daemon/src/multimap.js @@ -1,10 +1,12 @@ // @ts-check +/** @import { Multimap, WeakMultimap, BidirectionalMultimap } from './types.js' */ + const { quote: q } = assert; /** * @param {new () => (Map | WeakMap)} mapConstructor - * @returns {import('./types.js').Multimap} + * @returns {Multimap} */ const internalMakeMultimap = mapConstructor => { // eslint-disable-next-line new-cap @@ -42,25 +44,25 @@ const internalMakeMultimap = mapConstructor => { }; /** - * @returns {import('./types.js').Multimap} + * @returns {Multimap} */ export const makeMultimap = () => { return internalMakeMultimap(Map); }; /** - * @returns {import('./types.js').WeakMultimap} + * @returns {WeakMultimap} */ export const makeWeakMultimap = () => { return internalMakeMultimap(WeakMap); }; /** - * @returns {import('./types.js').BidirectionalMultimap} + * @returns {BidirectionalMultimap} */ export const makeBidirectionalMultimap = () => { /** - * @type {import('./types.js').Multimap} + * @type {Multimap} */ const keyForValues = internalMakeMultimap(Map); const valueForKey = new Map(); diff --git a/packages/daemon/src/pet-sitter.js b/packages/daemon/src/pet-sitter.js index d90abae29c..d23a93d26e 100644 --- a/packages/daemon/src/pet-sitter.js +++ b/packages/daemon/src/pet-sitter.js @@ -3,20 +3,22 @@ import { isPetName } from './pet-name.js'; import { parseId } from './formula-identifier.js'; +/** @import { PetStore, IdRecord, PetStoreIdNameChange } from './types.js' */ + const { quote: q } = assert; /** - * @param {import('./types.js').PetStore} petStore + * @param {PetStore} petStore * @param {Record} specialNames - * @returns {import('./types.js').PetStore} + * @returns {PetStore} */ export const makePetSitter = (petStore, specialNames) => { - /** @type {import('./types.js').PetStore['has']} */ + /** @type {PetStore['has']} */ const has = petName => { return Object.hasOwn(specialNames, petName) || petStore.has(petName); }; - /** @type {import('./types.js').PetStore['identifyLocal']} */ + /** @type {PetStore['identifyLocal']} */ const identifyLocal = petName => { if (Object.hasOwn(specialNames, petName)) { return specialNames[petName]; @@ -33,7 +35,7 @@ export const makePetSitter = (petStore, specialNames) => { /** * @param {string} petName - * @returns {import('./types.js').IdRecord} + * @returns {IdRecord} */ const idRecordForName = petName => { const id = identifyLocal(petName); @@ -43,15 +45,15 @@ export const makePetSitter = (petStore, specialNames) => { return parseId(id); }; - /** @type {import('./types.js').PetStore['list']} */ + /** @type {PetStore['list']} */ const list = () => harden([...Object.keys(specialNames).sort(), ...petStore.list()]); - /** @type {import('./types.js').PetStore['followNameChanges']} */ + /** @type {PetStore['followNameChanges']} */ const followNameChanges = async function* currentAndSubsequentNames() { for (const name of Object.keys(specialNames).sort()) { const idRecord = idRecordForName(name); - yield /** @type {{ add: string, value: import('./types.js').IdRecord }} */ ({ + yield /** @type {{ add: string, value: IdRecord }} */ ({ add: name, value: idRecord, }); @@ -59,7 +61,7 @@ export const makePetSitter = (petStore, specialNames) => { yield* petStore.followNameChanges(); }; - /** @type {import('./types.js').PetStore['followIdNameChanges']} */ + /** @type {PetStore['followIdNameChanges']} */ const followIdNameChanges = async function* currentAndSubsequentIds(id) { const subscription = petStore.followIdNameChanges(id); @@ -71,14 +73,12 @@ export const makePetSitter = (petStore, specialNames) => { const { value: existingNames } = await subscription.next(); existingNames?.names?.unshift(...idSpecialNames); existingNames?.names?.sort(); - yield /** @type {import('./types.js').PetStoreIdNameChange} */ ( - existingNames - ); + yield /** @type {PetStoreIdNameChange} */ (existingNames); yield* subscription; }; - /** @type {import('./types.js').PetStore['reverseIdentify']} */ + /** @type {PetStore['reverseIdentify']} */ const reverseIdentify = id => { const names = Array.from(petStore.reverseIdentify(id)); for (const [specialName, specialId] of Object.entries(specialNames)) { diff --git a/packages/daemon/src/pet-store.js b/packages/daemon/src/pet-store.js index a8048bd250..00536f1ddc 100644 --- a/packages/daemon/src/pet-store.js +++ b/packages/daemon/src/pet-store.js @@ -4,25 +4,39 @@ import { makeChangeTopic } from './pubsub.js'; import { parseId, assertValidId, isValidNumber } from './formula-identifier.js'; import { makeBidirectionalMultimap } from './multimap.js'; +/** + * @import { + * BidirectionalMultimap, + * Config, + * FilePowers, + * IdChangesTopic, + * NameChangesTopic, + * PetStore, + * PetStoreIdNameChange, + * PetStoreNameChange, + * PetStorePowers, + * } from './types.js' + */ + const { quote: q } = assert; /** - * @param {import('./types.js').FilePowers} filePowers - * @param {import('./types.js').Config} config + * @param {FilePowers} filePowers + * @param {Config} config */ export const makePetStoreMaker = (filePowers, config) => { /** * @param {string} petNameDirectoryPath * @param {(name: string) => void} assertValidName - * @returns {Promise} + * @returns {Promise} */ const makePetStoreAtPath = async (petNameDirectoryPath, assertValidName) => { - /** @type {import('./types.js').BidirectionalMultimap} */ + /** @type {BidirectionalMultimap} */ const idsToPetNames = makeBidirectionalMultimap(); - /** @type {import('./types.js').NameChangesTopic} */ + /** @type {NameChangesTopic} */ const nameChangesTopic = makeChangeTopic(); - /** @returns {import('./types.js').IdChangesTopic} */ + /** @returns {IdChangesTopic} */ const makeIdChangeTopic = () => makeChangeTopic(); /** @type {Map>} */ const idsToTopics = new Map(); @@ -31,7 +45,7 @@ export const makePetStoreMaker = (filePowers, config) => { * Publishes an id change to its subscribers, if any. * * @param {string} id - The id to publish a change for. - * @param {import('./types.js').PetStoreIdNameChange} payload - The payload to publish. + * @param {PetStoreIdNameChange} payload - The payload to publish. */ const publishIdChangeToSubscribers = (id, payload) => { const idTopic = idsToTopics.get(id); @@ -84,19 +98,19 @@ export const makePetStoreMaker = (filePowers, config) => { }), ); - /** @type {import('./types.js').PetStore['has']} */ + /** @type {PetStore['has']} */ const has = petName => { assertValidName(petName); return idsToPetNames.hasValue(petName); }; - /** @type {import('./types.js').PetStore['identifyLocal']} */ + /** @type {PetStore['identifyLocal']} */ const identifyLocal = petName => { assertValidName(petName); return idsToPetNames.getKey(petName); }; - /** @type {import('./types.js').PetStore['write']} */ + /** @type {PetStore['write']} */ const write = async (petName, formulaIdentifier) => { assertValidName(petName); assertValidId(formulaIdentifier); @@ -122,10 +136,10 @@ export const makePetStoreMaker = (filePowers, config) => { publishNameAddition(formulaIdentifier, petName); }; - /** @type {import('./types.js').PetStore['list']} */ + /** @type {PetStore['list']} */ const list = () => harden(idsToPetNames.getAll().sort()); - /** @type {import('./types.js').PetStore['followNameChanges']} */ + /** @type {PetStore['followNameChanges']} */ const followNameChanges = async function* currentAndSubsequentNames() { const subscription = nameChangesTopic.subscribe(); for (const name of idsToPetNames.getAll().sort()) { @@ -133,7 +147,7 @@ export const makePetStoreMaker = (filePowers, config) => { /** @type {string} */ (idsToPetNames.getKey(name)), ); - yield /** @type {import('./types.js').PetStoreNameChange} */ ({ + yield /** @type {PetStoreNameChange} */ ({ add: name, value: idRecord, }); @@ -141,18 +155,16 @@ export const makePetStoreMaker = (filePowers, config) => { yield* subscription; }; - /** @type {import('./types.js').PetStore['followIdNameChanges']} */ + /** @type {PetStore['followIdNameChanges']} */ const followIdNameChanges = async function* currentAndSubsequentIds(id) { if (!idsToTopics.has(id)) { idsToTopics.set(id, makeIdChangeTopic()); } - const idTopic = /** @type {import('./types.js').IdChangesTopic} */ ( - idsToTopics.get(id) - ); + const idTopic = /** @type {IdChangesTopic} */ (idsToTopics.get(id)); const subscription = idTopic.subscribe(); const existingNames = idsToPetNames.getAllFor(id).sort(); - yield /** @type {import('./types.js').PetStoreIdNameChange} */ ({ + yield /** @type {PetStoreIdNameChange} */ ({ add: parseId(id), names: existingNames, }); @@ -160,7 +172,7 @@ export const makePetStoreMaker = (filePowers, config) => { yield* subscription; }; - /** @type {import('./types.js').PetStore['remove']} */ + /** @type {PetStore['remove']} */ const remove = async petName => { assertValidName(petName); const formulaIdentifier = idsToPetNames.getKey(petName); @@ -179,7 +191,7 @@ export const makePetStoreMaker = (filePowers, config) => { // TODO consider tracking historical pet names for formulas }; - /** @type {import('./types.js').PetStore['rename']} */ + /** @type {PetStore['rename']} */ const rename = async (fromName, toName) => { assertValidName(fromName); assertValidName(toName); @@ -213,7 +225,7 @@ export const makePetStoreMaker = (filePowers, config) => { // TODO consider retaining a backlog of overwritten names for recovery }; - /** @type {import('./types.js').PetStore['reverseIdentify']} */ + /** @type {PetStore['reverseIdentify']} */ const reverseIdentify = formulaIdentifier => { assertValidId(formulaIdentifier); const formulaPetNames = idsToPetNames.getAllFor(formulaIdentifier); @@ -239,7 +251,7 @@ export const makePetStoreMaker = (filePowers, config) => { }; /** - * @type {import('./types.js').PetStorePowers['makeIdentifiedPetStore']} + * @type {PetStorePowers['makeIdentifiedPetStore']} */ const makeIdentifiedPetStore = ( formulaNumber, diff --git a/packages/daemon/src/pubsub.js b/packages/daemon/src/pubsub.js index 1a03ba5853..ec2835c359 100644 --- a/packages/daemon/src/pubsub.js +++ b/packages/daemon/src/pubsub.js @@ -3,6 +3,9 @@ import { makePromiseKit } from '@endo/promise-kit'; import { makeStream } from '@endo/stream'; +/** @import { AsyncQueue } from '@endo/stream' */ +/** @import { Topic } from './types.js' */ + // TypeScript ReadOnly semantics are not sufficiently expressive to distinguish // a value one promises not to alter from a value one must not alter, // making it useless. @@ -11,7 +14,7 @@ const freeze = /** @type {(v: T | Readonly) => T} */ (Object.freeze); /** * @template TValue TValue * @param {TValue} value - * @returns {import('@endo/stream').AsyncQueue} + * @returns {AsyncQueue} */ export const makeNullQueue = value => harden({ @@ -61,7 +64,7 @@ harden(makeChangePubSub); /** * @template TValue - * @returns {import('./types.js').Topic} + * @returns {Topic} */ export const makeChangeTopic = () => { /** @type {ReturnType>} */ diff --git a/packages/daemon/src/reader-ref.js b/packages/daemon/src/reader-ref.js index aff9344894..3c394b8c79 100644 --- a/packages/daemon/src/reader-ref.js +++ b/packages/daemon/src/reader-ref.js @@ -5,13 +5,21 @@ import { mapReader } from '@endo/stream'; import { makeExo } from '@endo/exo'; import { M } from '@endo/patterns'; +/** @import { Reader } from '@endo/stream' */ +/** @import { FarRef } from '@endo/eventual-send' */ +/** + * @import { + * SomehowAsyncIterable, + * } from './types.js' + */ + /** * Returns the iterator for the given iterable object. * Supports both synchronous and asynchronous iterables. * * @template T The item type of the iterable. - * @param {import('./types').SomehowAsyncIterable} iterable The iterable object. - * @returns {import('@endo/stream').Reader} sort of fudging this into a stream to appease "mapReader" + * @param {SomehowAsyncIterable} iterable The iterable object. + * @returns {Reader} sort of fudging this into a stream to appease "mapReader" */ export const asyncIterate = iterable => { let iterator; @@ -27,8 +35,8 @@ export const asyncIterate = iterable => { /** * @template T - * @param {import('./types').SomehowAsyncIterable} iterable The iterable object. - * @returns {import('@endo/far').FarRef>} + * @param {SomehowAsyncIterable} iterable The iterable object. + * @returns {FarRef>} */ export const makeIteratorRef = iterable => { const iterator = asyncIterate(iterable); @@ -66,8 +74,8 @@ export const makeIteratorRef = iterable => { }; /** - * @param {import('./types').SomehowAsyncIterable} readable - * @returns {import('@endo/far').FarRef>} + * @param {SomehowAsyncIterable} readable + * @returns {FarRef>} */ export const makeReaderRef = readable => makeIteratorRef(mapReader(asyncIterate(readable), encodeBase64)); diff --git a/packages/daemon/src/remote-control.js b/packages/daemon/src/remote-control.js index 652df515cd..758e529b7a 100644 --- a/packages/daemon/src/remote-control.js +++ b/packages/daemon/src/remote-control.js @@ -1,15 +1,17 @@ // @ts-check +/** @import { RemoteControl, RemoteControlState, EndoGateway } from './types.js' */ + /** * @param {string} localNodeId */ export const makeRemoteControlProvider = localNodeId => { - /** @type {Map} */ + /** @type {Map} */ const remoteControls = new Map(); /** @param {string} remoteNodeId */ const makeRemoteControl = remoteNodeId => { - /** @type {import('./types.js').RemoteControlState} */ + /** @type {RemoteControlState} */ let state; // In this state, we have received a remoteGateway from an ingress @@ -17,10 +19,10 @@ export const makeRemoteControlProvider = localNodeId => { // We do not have a pending outbound connection attempt. /** * @type {( - * remoteGateway: Promise, + * remoteGateway: Promise, * cancel: (error: Error) => void, * cancelled: Promise, - * ) => import('./types.js').RemoteControlState} + * ) => RemoteControlState} */ const accepted = (remoteGateway, cancelCurrent, currentCancelled) => { return { @@ -55,10 +57,10 @@ export const makeRemoteControlProvider = localNodeId => { // We have an active outbound connection. /** * @type {( - * remoteGateway: Promise, + * remoteGateway: Promise, * cancel: (error: Error) => void, * cancelled: Promise, - * ) => import('./types.js').RemoteControlState} + * ) => RemoteControlState} */ const connected = remoteNodeId > localNodeId @@ -149,7 +151,7 @@ export const makeRemoteControlProvider = localNodeId => { }; }; - /** @type {() => import('./types.js').RemoteControlState} */ + /** @type {() => RemoteControlState} */ const start = () => { return { accept: (proposedRemoteGateway, cancelCurrent, currentCancelled) => { @@ -178,7 +180,7 @@ export const makeRemoteControlProvider = localNodeId => { state = start(); /** - * @param {Promise} proposedRemoteGateway + * @param {Promise} proposedRemoteGateway * @param {(error: Error) => void} cancelConnection * @param {Promise} connectionCancelled */ @@ -194,7 +196,7 @@ export const makeRemoteControlProvider = localNodeId => { ); }; /** - * @param {() => Promise} getRemoteGateway + * @param {() => Promise} getRemoteGateway * @param {(error: Error) => void} cancelIncarnation * @param {Promise} incarnationCancelled */ diff --git a/packages/daemon/src/serial-jobs.js b/packages/daemon/src/serial-jobs.js index fc2783abf8..4c7ca9114b 100644 --- a/packages/daemon/src/serial-jobs.js +++ b/packages/daemon/src/serial-jobs.js @@ -1,10 +1,13 @@ import { makeQueue } from '@endo/stream'; +/** @import { AsyncQueue } from '@endo/stream' */ +/** @import { SerialJobs } from './types.js' */ + /** - * @returns {import('./types.js').SerialJobs} + * @returns {SerialJobs} */ export const makeSerialJobs = () => { - /** @type {import('@endo/stream').AsyncQueue} */ + /** @type {AsyncQueue} */ const queue = makeQueue(); const lock = () => { return queue.get(); diff --git a/packages/daemon/src/types.d.ts b/packages/daemon/src/types.d.ts index 4d3018199b..90a47f09ea 100644 --- a/packages/daemon/src/types.d.ts +++ b/packages/daemon/src/types.d.ts @@ -493,8 +493,6 @@ export interface EndoReadable { text(): Promise; json(): Promise; } -export type FarEndoReadable = FarRef; - export interface EndoWorker {} export type MakeHostOrGuestOptions = { @@ -556,7 +554,7 @@ export interface EndoHost extends EndoAgent { store( readerRef: ERef>, petName: string, - ): Promise; + ): Promise>; provideGuest( petName?: string, opts?: MakeHostOrGuestOptions, @@ -626,8 +624,6 @@ export type EndoBootstrap = { addPeerInfo: (peerInfo: PeerInfo) => Promise; }; -export type FarEndoBootstrap = FarRef; - export type CryptoPowers = { makeSha512: () => Sha512; randomHex512: () => Promise; @@ -678,7 +674,7 @@ export type SocketPowers = { export type NetworkPowers = SocketPowers & { makePrivatePathService: ( - endoBootstrap: FarEndoBootstrap, + endoBootstrap: FarRef, sockPath: string, cancelled: Promise, exitWithError: (error: Error) => void, @@ -710,8 +706,16 @@ export interface WorkerDaemonFacet { id: string, cancelled: Promise, ): Promise; - makeBundle(bundle: ERef, powers: ERef); - makeUnconfined(path: string, powers: ERef); + makeBundle( + bundle: ERef, + powers: ERef, + context: ERef, + ): Promise; + makeUnconfined( + path: string, + powers: ERef, + context: ERef, + ): Promise; } export type DaemonicControlPowers = { @@ -825,7 +829,7 @@ export interface DaemonCore { formulateEndoBootstrap: ( specifiedFormulaNumber: string, - ) => FormulateResult; + ) => FormulateResult>; formulateEval: ( nameHubId: string, @@ -889,7 +893,7 @@ export interface DaemonCore { formulateReadableBlob: ( readerRef: ERef>, deferredTasks: DeferredTasks, - ) => FormulateResult; + ) => FormulateResult>; formulateInvitation: ( hostAgentId: string, diff --git a/packages/daemon/src/web-server-node-powers.js b/packages/daemon/src/web-server-node-powers.js index 83b032a87f..98e04cfcc9 100644 --- a/packages/daemon/src/web-server-node-powers.js +++ b/packages/daemon/src/web-server-node-powers.js @@ -1,6 +1,8 @@ import { makePromiseKit } from '@endo/promise-kit'; import { makePipe } from '@endo/stream'; +/** @import { HttpRespond, HttpConnect } from './types.js' */ + const medialIterationResult = harden({ done: false }); const finalIterationResult = harden({ done: false }); @@ -18,8 +20,8 @@ export const makeHttpPowers = ({ http, ws }) => { * @param {object} args * @param {number} args.port * @param {string} args.host - * @param {import('./types.js').HttpRespond} [args.respond] - * @param {import('./types.js').HttpConnect} [args.connect] + * @param {HttpRespond} [args.respond] + * @param {HttpConnect} [args.connect] * @param {Promise} args.cancelled */ const servePortHttp = async ({ diff --git a/packages/daemon/src/web-server-node.js b/packages/daemon/src/web-server-node.js index e04d313019..b2960177bf 100644 --- a/packages/daemon/src/web-server-node.js +++ b/packages/daemon/src/web-server-node.js @@ -3,6 +3,8 @@ import fs from 'node:fs'; import http from 'node:http'; import { fileURLToPath } from 'url'; +/** @import { HttpRespond, FarContext } from './types.js' */ + // @ts-ignore We cannot use a synthetic default export in practice here (circa Node.js 16) import * as ws from 'ws'; @@ -26,7 +28,7 @@ const read = async location => fs.promises.readFile(fileURLToPath(location)); /** * @param {unknown} _powers - * @param {import('./types.js').FarContext} context + * @param {FarContext} context */ export const make = async (_powers, context) => { const script = await makeBundle( @@ -69,7 +71,7 @@ export const make = async (_powers, context) => { const cancelled = Promise.race([webletCancelled, serverCancelled]); - /** @type {import('./types.js').HttpRespond} */ + /** @type {HttpRespond} */ const respond = async request => { if (request.method === 'GET') { if (request.url === `/${accessToken}/`) { diff --git a/packages/daemon/src/worker-node-powers.js b/packages/daemon/src/worker-node-powers.js index 4026e4b04d..345dad3362 100644 --- a/packages/daemon/src/worker-node-powers.js +++ b/packages/daemon/src/worker-node-powers.js @@ -2,11 +2,13 @@ import { makeNodeReader, makeNodeWriter } from '@endo/stream-node'; +/** @import { MignonicPowers } from './types.js' } */ + /** * @param {object} modules * @param {typeof import('fs')} modules.fs * @param {typeof import('url')} modules.url - * @returns {import('./types.js').MignonicPowers} + * @returns {MignonicPowers} */ export const makePowers = ({ fs, url }) => { // @ts-ignore This is in fact how you open a file descriptor. diff --git a/packages/daemon/src/worker-node.js b/packages/daemon/src/worker-node.js index 28bac85cd2..b0ca493c0a 100644 --- a/packages/daemon/src/worker-node.js +++ b/packages/daemon/src/worker-node.js @@ -14,12 +14,12 @@ import { makePromiseKit } from '@endo/promise-kit'; import { main } from './worker.js'; import { makePowers } from './worker-node-powers.js'; +/** @import { PromiseKit } from '@endo/promise-kit' */ + const powers = makePowers({ fs, url }); const { promise: cancelled, reject: cancel } = - /** @type {import('@endo/promise-kit').PromiseKit} */ ( - makePromiseKit() - ); + /** @type {PromiseKit} */ (makePromiseKit()); process.once('SIGINT', () => cancel(new Error('SIGINT'))); diff --git a/packages/daemon/src/worker.js b/packages/daemon/src/worker.js index f70ef29226..d0a9a5c69e 100644 --- a/packages/daemon/src/worker.js +++ b/packages/daemon/src/worker.js @@ -6,6 +6,9 @@ import { makeExo } from '@endo/exo'; import { M } from '@endo/patterns'; import { makeNetstringCapTP } from './connection.js'; +/** @import { ERef } from '@endo/eventual-send' */ +/** @import { EndoReadable, MignonicPowers } from './types.js' */ + const endowments = harden({ assert, console, @@ -87,7 +90,7 @@ export const makeWorkerFacet = ({ cancel }) => { }, /** - * @param {import('@endo/eventual-send').ERef} readableP + * @param {ERef} readableP * @param {Promise} powersP * @param {Promise} contextP */ @@ -108,7 +111,7 @@ export const makeWorkerFacet = ({ cancel }) => { }; /** - * @param {import('./types.js').MignonicPowers} powers + * @param {MignonicPowers} powers * @param {number | undefined} pid * @param {(error: Error) => void} cancel * @param {Promise} cancelled