extension events after boot fixes (#2925)
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
Notify HeyPuter / notify (push) Has been cancelled
release-please / release-please (push) Has been cancelled

This commit is contained in:
Daniel Salazar
2026-05-05 17:42:55 -07:00
committed by GitHub
parent 8d0b8d4905
commit c1dacab4c2
3 changed files with 33 additions and 20 deletions
+10 -2
View File
@@ -17,9 +17,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { extensionStore } from '../extensions';
import { PuterClient } from './types';
export class EventClient extends PuterClient {
/** @type {Record<string,(()=>void)[]>} */
#eventListeners = {};
onServerStart() {
@@ -60,7 +62,10 @@ export class EventClient extends PuterClient {
i === parts.length - 1
? key
: `${parts.slice(0, i + 1).join('.')}.*`;
const listeners = this.#eventListeners[matchKey];
const extensionListeners = extensionStore.events[matchKey];
const listeners = (this.#eventListeners[matchKey] || []).concat(
extensionListeners || [],
);
if (!listeners) continue;
for (const listener of listeners) {
this.#emitEvent(listener, key, data, meta);
@@ -93,7 +98,10 @@ export class EventClient extends PuterClient {
i === parts.length - 1
? key
: `${parts.slice(0, i + 1).join('.')}.*`;
const listeners = this.#eventListeners[matchKey];
const extensionListeners = extensionStore.events[matchKey];
const listeners = (this.#eventListeners[matchKey] || []).concat(
extensionListeners || [],
);
if (!listeners) continue;
for (const listener of listeners) {
try {
@@ -123,7 +123,7 @@ export class AppController extends PuterController {
}
try {
this.clients.event?.emit(
this.clients.event?.emitAndWait(
'app.opened',
{
app_uid,
+22 -17
View File
@@ -124,24 +124,29 @@ export class PuterServer {
this.clients = {} as typeof this.clients;
for (const [clientName, ClientClass] of Object.entries(clients)) {
// @ts-expect-error as any casting to avoid overly complex or circular types
this.clients[clientName] =
typeof ClientClass === 'object'
? ClientClass
: (new (ClientClass as any)(this.#config) as any);
// @ts-expect-error implicit any casting to avoid overly complex or circular types
clientsContainers[clientName] = this.clients[clientName];
}
for (const [clientName, ClientClass] of Object.entries(
extensionStore.clients,
)) {
// @ts-expect-error as any casting to avoid overly complex or circular types
this.clients[clientName] =
typeof ClientClass === 'object'
? ClientClass
: (new (ClientClass as any)(this.#config) as any);
// @ts-expect-error implicit any casting to avoid overly complex or circular types
clientsContainers[clientName] = this.clients[clientName];
}
this.stores = {} as typeof this.stores;
for (const [storeName, StoreClass] of Object.entries(stores)) {
// @ts-expect-error as any casting to avoid overly complex or circular types
this.stores[storeName] =
typeof StoreClass === 'object'
? StoreClass
@@ -150,11 +155,13 @@ export class PuterServer {
this.clients,
this.stores,
) as any);
// @ts-expect-error implicit any casting to avoid overly complex or circular types
storesContainers[storeName] = this.stores[storeName];
}
for (const [storeName, StoreClass] of Object.entries(
extensionStore.stores,
)) {
// @ts-expect-error as any casting to avoid overly complex or circular types
this.stores[storeName] =
typeof StoreClass === 'object'
? StoreClass
@@ -163,11 +170,13 @@ export class PuterServer {
this.clients,
this.stores,
) as any);
// @ts-expect-error implicit any casting to avoid overly complex or circular types
storesContainers[storeName] = this.stores[storeName];
}
this.services = {} as typeof this.services;
for (const [serviceName, ServiceClass] of Object.entries(services)) {
// @ts-expect-error as any casting to avoid overly complex or circular types
this.services[serviceName] =
typeof ServiceClass === 'object'
? ServiceClass
@@ -177,11 +186,13 @@ export class PuterServer {
this.stores,
this.services,
) as any);
// @ts-expect-error implicit any casting to avoid overly complex or circular types
servicesContainers[serviceName] = this.services[serviceName];
}
for (const [serviceName, ServiceClass] of Object.entries(
extensionStore.services,
)) {
// @ts-expect-error as any casting to avoid overly complex or circular types
this.services[serviceName] =
typeof ServiceClass === 'object'
? ServiceClass
@@ -191,6 +202,7 @@ export class PuterServer {
this.stores,
this.services,
) as any);
// @ts-expect-error implicit any casting to avoid overly complex or circular types
servicesContainers[serviceName] = this.services[serviceName];
}
@@ -235,6 +247,7 @@ export class PuterServer {
this.stores,
this.services,
) as any);
// @ts-expect-error as any casting to avoid overly complex or circular types
this.drivers[driverKey] = instance;
driversContainers[driverKey] = instance;
}
@@ -243,6 +256,7 @@ export class PuterServer {
for (const [controllerName, ControllerClass] of Object.entries(
controllers,
)) {
// @ts-expect-error as any casting to avoid overly complex or circular types
this.controllers[controllerName] =
typeof ControllerClass === 'object'
? ControllerClass
@@ -255,14 +269,17 @@ export class PuterServer {
) as any);
this.#registerControllerRoutes(
controllerName,
// @ts-expect-error as any casting to avoid overly complex or circular types
this.controllers[controllerName],
);
controllersContainers[controllerName] =
// @ts-expect-error as any casting to avoid overly complex or circular types
this.controllers[controllerName];
}
for (const [controllerName, ControllerClass] of Object.entries(
extensionStore.controllers,
)) {
// @ts-expect-error as any casting to avoid overly complex or circular types
this.controllers[controllerName] =
typeof ControllerClass === 'object'
? ControllerClass
@@ -275,26 +292,14 @@ export class PuterServer {
) as any);
this.#registerControllerRoutes(
controllerName,
// @ts-expect-error as any casting to avoid overly complex or circular types
this.controllers[controllerName],
);
controllersContainers[controllerName] =
// @ts-expect-error as any casting to avoid overly complex or circular types
this.controllers[controllerName];
}
// Register extension event listeners. Extensions opted for a
// 2-arg `(data, meta)` handler shape; EventClient calls with
// `(key, data, meta)`. Drop `key` in the adapter so extension
// code stays stable.
Object.entries(extensionStore.events).forEach(([event, handlers]) => {
handlers.forEach((handler) => {
this.clients.event.on(
event,
(_key: string, data: unknown, meta: object) =>
handler(data, meta),
);
});
});
// Extension routes are shaped as `RouteDescriptor`s too, so they
// flow through the same materializer as controller routes — same
// option → middleware translation (subdomain, auth, body parsers, …).
@@ -1100,16 +1105,16 @@ export class PuterServer {
});
} else {
this.#server = {
close: (cb) => {
close: (cb: (error?: Error) => void | undefined) => {
console.debug('PuterServer mock close called');
cb();
cb?.();
},
closeAllConnections: () => {
console.debug(
'PuterServer mock closeAllConnections called',
);
},
};
} as unknown as http.Server;
}
}