diff --git a/packages/daemon/src/daemon.js b/packages/daemon/src/daemon.js index 7739feb2ff..350156f674 100644 --- a/packages/daemon/src/daemon.js +++ b/packages/daemon/src/daemon.js @@ -1015,7 +1015,7 @@ const makeDaemonCore = async ( }; /** @type {import('./types.js').DaemonCore['incarnateGuest']} */ - const incarnateGuest = async hostFormulaIdentifier => { + const incarnateGuest = async (hostFormulaIdentifier, hooks) => { const { guestFormulaNumber, hostHandleFormulaIdentifier, @@ -1041,6 +1041,14 @@ const makeDaemonCore = async ( ]), ); + await hooks.execute({ + guestFormulaIdentifier: serializeFormulaIdentifier({ + type: 'guest', + number: ownFormulaNumber, + node: ownNodeIdentifier, + }), + }); + return harden({ guestFormulaNumber: ownFormulaNumber, hostHandleFormulaIdentifier: hostHandle.formulaIdentifier, diff --git a/packages/daemon/src/host.js b/packages/daemon/src/host.js index 877fb98bb0..1a6c7e36d5 100644 --- a/packages/daemon/src/host.js +++ b/packages/daemon/src/host.js @@ -132,48 +132,48 @@ export const makeHostMaker = ({ * @returns {Promise<{formulaIdentifier: string, value: Promise}>} */ const makeGuest = async (petName, { introducedNames = {} } = {}) => { - /** @type {string | undefined} */ - let formulaIdentifier; if (petName !== undefined) { - formulaIdentifier = petStore.identifyLocal(petName); - } + const formulaIdentifier = petStore.identifyLocal(petName); + if (formulaIdentifier !== undefined) { + if (formulaIdentifier.startsWith('guest:')) { + throw new Error( + `Existing pet name does not designate a guest powers capability: ${q( + petName, + )}`, + ); + } - if (formulaIdentifier === undefined) { - const { value, formulaIdentifier: guestFormulaIdentifier } = - // Behold, recursion: - // eslint-disable-next-line no-use-before-define - await incarnateGuest(hostFormulaIdentifier); - // TODO: move to hook - if (petName !== undefined) { - assertPetName(petName); - await petStore.write(petName, guestFormulaIdentifier); + // TODO: Should this be awaited? + introduceNamesToParty(formulaIdentifier, introducedNames); + const guestController = + provideControllerForFormulaIdentifier(formulaIdentifier); + return { + formulaIdentifier, + value: /** @type {Promise} */ ( + guestController.external + ), + }; } + } - return { - value: Promise.resolve(value), - formulaIdentifier: guestFormulaIdentifier, - }; - } else if (!formulaIdentifier.startsWith('guest:')) { - throw new Error( - `Existing pet name does not designate a guest powers capability: ${q( - petName, - )}`, + /** @type {AsyncHooks} */ + const hooks = makeAsyncHooks(); + if (petName !== undefined) { + hooks.add(identifiers => + petStore.write(petName, identifiers.guestFormulaIdentifier), ); } - if (introducedNames !== undefined) { - // TODO: move to hook - introduceNamesToParty(formulaIdentifier, introducedNames); - } - const newGuestController = - /** @type {import('./types.js').Controller} */ ( - provideControllerForFormulaIdentifier(formulaIdentifier) - ); + const { value, formulaIdentifier } = + // Behold, recursion: + // eslint-disable-next-line no-use-before-define + await incarnateGuest(hostFormulaIdentifier, hooks); + // TODO: Should this be awaited? + introduceNamesToParty(formulaIdentifier, introducedNames); + return { + value: Promise.resolve(value), formulaIdentifier, - value: /** @type {Promise} */ ( - newGuestController.external - ), }; }; @@ -280,7 +280,7 @@ export const makeHostMaker = ({ )); if (guestFormulaIdentifier === undefined) { throw new Error( - `panic: provideGuest must return an guest with a corresponding formula identifier`, + `panic: makeGuest must return a guest with a corresponding formula identifier`, ); } } @@ -308,7 +308,7 @@ export const makeHostMaker = ({ throw new Error('Evaluator requires one pet name for each code name'); } - /** @type {AsyncHooks} */ + /** @type {AsyncHooks} */ const hooks = makeAsyncHooks(); const workerFormulaIdentifier = provideWorkerFormulaIdentifierSync( diff --git a/packages/daemon/src/pet-store.js b/packages/daemon/src/pet-store.js index 8bfcf31fef..113b648f81 100644 --- a/packages/daemon/src/pet-store.js +++ b/packages/daemon/src/pet-store.js @@ -85,12 +85,14 @@ export const makePetStoreMaker = (filePowers, locator) => { assertValidName(petName); assertValidFormulaIdentifier(formulaIdentifier, petName); + // TODO: Return early if the formula identifier is the same. if (petNames.has(petName)) { // Perform cleanup on the overwritten pet name. const formulaPetNames = formulaIdentifiers.get(petName); if (formulaPetNames !== undefined) { formulaPetNames.delete(petName); } + // TODO: Should this only happen if something is actually deleted? changesTopic.publisher.next({ remove: petName }); } diff --git a/packages/daemon/src/types.d.ts b/packages/daemon/src/types.d.ts index 8bc40efc59..80abb9d660 100644 --- a/packages/daemon/src/types.d.ts +++ b/packages/daemon/src/types.d.ts @@ -92,6 +92,10 @@ type GuestFormula = { worker: string; }; +export type GuestHookParams = { + guestFormulaIdentifier: string; +}; + type LeastAuthorityFormula = { type: 'least-authority'; }; @@ -105,7 +109,7 @@ type EvalFormula = { // TODO formula slots }; -export type EvalFormulaHooks = { +export type EvalHookParams = { endowmentFormulaIdentifiers: string[]; evalFormulaIdentifier: string; workerFormulaIdentifier: string; @@ -751,7 +755,10 @@ export interface DaemonCore { leastAuthorityFormulaIdentifier: string, specifiedWorkerFormulaIdentifier?: string | undefined, ) => IncarnateResult; - incarnateGuest: (hostFormulaIdentifier: string) => IncarnateResult; + incarnateGuest: ( + hostFormulaIdentifier: string, + hooks: AsyncHooks, + ) => IncarnateResult; incarnateReadableBlob: ( contentSha512: string, ) => IncarnateResult; @@ -760,7 +767,7 @@ export interface DaemonCore { source: string, codeNames: string[], endowmentFormulaIdsOrPaths: (string | string[])[], - hooks: AsyncHooks, + hooks: AsyncHooks, specifiedWorkerFormulaIdentifier?: string, ) => IncarnateResult; incarnateUnconfined: (