mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
* added emitter context * partial items tests * updated items handler tests * fixed test after merge * forgot the event context * fixed auth message parsing for graphql subscriptions * fixed type strictness * fixed graphql subscription bug * bumped websocket dependencies * touched up some dangling code * updated itemsservice usage * disabled overkill logs * double checked environment type processing * fixed missed capitalization * fixed subscription payloads * Added explicit string type casting * removed obsolete "trimUpper" utility * using the parseJSON utility consistently * pinned dependencies * parse environment variables * fixed pnpm-lock * GraphQL Subscriptions for all events * fixed typo * added event data to the graphql definition * fix payload for delete events * Added optional chaining for type to prevent fatal crashes on invalid messages * fix failing on getting type from undefined * Update api/src/websocket/exceptions.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Add proper ZodError handling * added the zod-validation-error parser * allow disabling the rate limiter * Update api/src/websocket/controllers/base.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * updated starting logs * fixed email/password expiration logic * added tests for getMessageType * simplified message parsing and dropped capitalization * updated authenticate test * switched to lower cased message.type to prevent spreading "toUpperCase" around * cleaned up debug logs * cast enabled config to boolean * Update api/src/websocket/controllers/rest.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Update api/src/websocket/handlers/subscribe.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Update api/src/websocket/handlers/subscribe.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Update api/src/websocket/handlers/items.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Update api/src/websocket/controllers/base.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Update api/src/websocket/handlers/heartbeat.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Suggested fixes by Azri * removed redundant try-catch * fixed authentication timeout added returning the refresh token when authenticating * updated pnpm lock after merge * Fixed authentication modes for GraphQL according to best practices * implement useFakeTimers in heartbeat unit test * implement useFakeTimers in items unit test * Update api/src/services/server.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * removed obsolete authentication.verbose toggle * added email flag to message validation * switched to ternary for consistency * moved getSchema out of for loop * added singleton logic to items handler * close the socket after failed auth for non-public connections * disabled system collections for rest subscriptions * re-ran pnpm i * allow for multiple subscripitions in the memory messenger * - fixed system collection subscriptions - abstracted hook message bus - fixed graphql horizontal scaling * remove logic from root context for tests * fix reading created item * fix linter * typo and extra safe guard suggested by azri * prevent setting long timeouts in favor of a shared interval * prevent unsubscribing all existing subscriptions when omitting "uid" * - extracted getService utility - block system collections mutation in the items handler - implemented the correct services for system collections * allow numeric uid's to be used * fixed the types for numeric uid's to be used * added missing await's * fixed type imports after merge * removed unused imports * Update api/src/websocket/controllers/hooks.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Update api/src/websocket/controllers/hooks.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Update api/src/messenger.ts Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * improved error for graphql subscriptions * fixed TS Modernization conflicts * fixed TS Modernization conflicts * fixed conflicts after merge * removed unused name property * abstracxted environment configuration * respond to ping messages when heartbeat disabled * something something merge * moved toBoolean to it's own util file * replaced old socket naming * removed old exception * fixed typo * Update api/src/env.ts Co-authored-by: ian <licitdev@gmail.com> * Update api/src/websocket/handlers/heartbeat.test.ts Co-authored-by: ian <licitdev@gmail.com> * Update api/src/websocket/handlers/heartbeat.ts Co-authored-by: ian <licitdev@gmail.com> * Update api/src/services/server.ts Co-authored-by: ian <licitdev@gmail.com> * fixed for linter * add server_info_websocket in graphql * Add base REST websocket tests * do merge things * fixing things * fixed failing unit test * Update dependencies * Move tests * Update lockfile * Use new paths when spawning * return websockets to opt-in * Enable websockets for tests * Test with ephemeral access token * no camelcasing gql subscriptions * use underscore for gql event * Remove unused import * Add base GraphQL subscription tests * Fix accidental comment * Add some relational tests * Organize imports Using VS Code's default organize import * Run ESlint formatting * One more opinionated formatting change * Formatting * Fix message sequence not in order * Remove relational batch update tests * Test horizontal scaling * using toboolean util for server_info * removed unneeded type cast * found the gql request type * extra usage of the toBoolean util * merge the authentication middleware and get-account-for-token util * updated utility test * fixed middleware unit test * Add return * Remove user filtering and close conns * Fix reused accountability * fixed failing util test * added subscription unit tests * added missing mock * trigger workflow * Revert "trigger workflow" This reverts commit4f544b0c1b. * Trigger testing for all vendors * add unsubscription confirmation * Wait for unsubscription confirmation * Fix incorrect sending of unsubscription confirmation * updated ubsubscribe logic * Update count for unsubscription message * Fix sequence for UUID pktype in MSSQL * Increase auth timeout * Add start index when getting messages * Fix subscription retrieval and cast uid to string * Remove nested ternary * Revert "Increase auth timeout" This reverts commit10707409c4. * Terminate connection instead of close * fixed merge * re-added missing packages after merge resolve * fixed type imports * Create lazy-cows-happen.md Added changeset * Minor bump for "directus" package as well * fixed "strict" auth mode for graphql subscriptions * removed nested ternary * Add websocket tests to sequential flow * Disable pressure limiter for blackbox tests * fix merge * WebSockets Documentation (#18254) * Small repsonsive styling fix on Card * REST getting started guide * Authentication guide * REST subscription guides * JS Chat guide * Sidebar websocket guides section * Added config options * Respoinding to brainslug's review * Fixed incorrect header on guides/rt/subs * Fixed spellchecker * Correct full code example on guides/rt/chat/js * Fixed JS chat tut * Order of steps in js chat guide updated for easier following-along * Realtime chat Vue Guide * feat: create react.js file * feat: add set up for directus project * docs: create react boilder plate * docs: initialize connection * docs: set up submission methods * docs: establish websocket connection * docs: subscribe to messages * docs: create new messages * docs: display new messages * docs: display historical messages * docs: next steps * docs: full code sample * docs: clean up * docs: add name to contributors * docs: add react card * docs: updates to react chat * Added live poll result guide * docs: intro * docs: before you begin * docs: install packages * docs: authenticate connection * docs: query and mutation * docs: utilize hooks * docs: subscribe to changes * docs: create helper functions * docs: display messages * docs: summary * docs: full sample code * chore: add card for webscockets with graphql * docs: intro * docs: subscribe to changes * docs: handling changes * docs: crud operations * docs: unsubscribing from changes * docs: updates * chore: add card * chore: updates to graphql docs * chore: updates to getting started * chore: updates to subscription * chore: updates to real chat guide * Added WebSockets Operations Guide * Consistent titles * Contributors component for docs * Triggering Netlify * Add operations to sidebar * Fix operations link * Small formatting changes * Clarity around property values * Removed unused values in Contributors component * Prompt for default choice * Tabs & lowercase doctypes * Semicolons * Event overwerites -> event listeners * Spacing * Flipped order of websockets guide to match GQL --------- Co-authored-by: Esther Agbaje <folasadeagbaje@gmail.com> Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com> * fixed typo * removed unused import * added tests for "to-boolean" and "exceptions" * added websocket service tests * quote environment variable to satisfy dictionary * GraphQL Subscriptions update (#18804) * updated graphql subscription structure * updated graphql examples * Create hungry-points-rescue.md * using `key` instead of `ID` on the toplevel * removed changeset * fixed the graphql type after the rename to `key` * retrun data null for delete events to prevent non-nullable gql error * updated missed ID reference in the docs * updated missed ID reference in the docs * renamed "payload" to "data" in the REST Subscription response * fixed missed reference to payload * added optional event filter for REST subscriptions * updated docs for event filter * Update docs/guides/real-time/subscriptions/websockets.md Co-authored-by: ian <licitdev@gmail.com> --------- Co-authored-by: ian <licitdev@gmail.com> * added messenger unit test * always send subscription confirmation * Add event to subscription options * Update tests * Add tests for event filtering * Revert testing for all vendors * Remove obsolete console comment * Update comment * Correct event in JS WS guide * Fix collection name to match name used in subscription * Fix collection name in other guides * Fix diffs in doc & enhance chart example * Complete sentence in GraphQL guide * Small update to config description --------- Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com> Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> Co-authored-by: ian <licitdev@gmail.com> Co-authored-by: Nitwel <mail@nitwel.de> Co-authored-by: Kevin Lewis <kvn@lws.io> Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch> Co-authored-by: Esther Agbaje <folasadeagbaje@gmail.com>
116 lines
3.0 KiB
TypeScript
116 lines
3.0 KiB
TypeScript
import type { ActionHandler, EventContext, FilterHandler, InitHandler } from '@directus/types';
|
|
import ee2 from 'eventemitter2';
|
|
import logger from './logger.js';
|
|
import getDatabase from './database/index.js';
|
|
|
|
export class Emitter {
|
|
private filterEmitter;
|
|
private actionEmitter;
|
|
private initEmitter;
|
|
|
|
constructor() {
|
|
const emitterOptions = {
|
|
wildcard: true,
|
|
verboseMemoryLeak: true,
|
|
delimiter: '.',
|
|
|
|
// This will ignore the "unspecified event" error
|
|
ignoreErrors: true,
|
|
};
|
|
|
|
this.filterEmitter = new ee2.EventEmitter2(emitterOptions);
|
|
this.actionEmitter = new ee2.EventEmitter2(emitterOptions);
|
|
this.initEmitter = new ee2.EventEmitter2(emitterOptions);
|
|
}
|
|
|
|
private getDefaultContext(): EventContext {
|
|
return {
|
|
database: getDatabase(),
|
|
accountability: null,
|
|
schema: null,
|
|
};
|
|
}
|
|
|
|
public async emitFilter<T>(
|
|
event: string | string[],
|
|
payload: T,
|
|
meta: Record<string, any>,
|
|
context: EventContext | null = null
|
|
): Promise<T> {
|
|
const events = Array.isArray(event) ? event : [event];
|
|
|
|
const eventListeners = events.map((event) => ({
|
|
event,
|
|
listeners: this.filterEmitter.listeners(event) as FilterHandler<T>[],
|
|
}));
|
|
|
|
let updatedPayload = payload;
|
|
|
|
for (const { event, listeners } of eventListeners) {
|
|
for (const listener of listeners) {
|
|
const result = await listener(updatedPayload, { event, ...meta }, context ?? this.getDefaultContext());
|
|
|
|
if (result !== undefined) {
|
|
updatedPayload = result;
|
|
}
|
|
}
|
|
}
|
|
|
|
return updatedPayload;
|
|
}
|
|
|
|
public emitAction(event: string | string[], meta: Record<string, any>, context: EventContext | null = null): void {
|
|
const events = Array.isArray(event) ? event : [event];
|
|
|
|
for (const event of events) {
|
|
this.actionEmitter.emitAsync(event, { event, ...meta }, context ?? this.getDefaultContext()).catch((err) => {
|
|
logger.warn(`An error was thrown while executing action "${event}"`);
|
|
logger.warn(err);
|
|
});
|
|
}
|
|
}
|
|
|
|
public async emitInit(event: string, meta: Record<string, any>): Promise<void> {
|
|
try {
|
|
await this.initEmitter.emitAsync(event, { event, ...meta });
|
|
} catch (err: any) {
|
|
logger.warn(`An error was thrown while executing init "${event}"`);
|
|
logger.warn(err);
|
|
}
|
|
}
|
|
|
|
public onFilter(event: string, handler: FilterHandler): void {
|
|
this.filterEmitter.on(event, handler);
|
|
}
|
|
|
|
public onAction(event: string, handler: ActionHandler): void {
|
|
this.actionEmitter.on(event, handler);
|
|
}
|
|
|
|
public onInit(event: string, handler: InitHandler): void {
|
|
this.initEmitter.on(event, handler);
|
|
}
|
|
|
|
public offFilter(event: string, handler: FilterHandler): void {
|
|
this.filterEmitter.off(event, handler);
|
|
}
|
|
|
|
public offAction(event: string, handler: ActionHandler): void {
|
|
this.actionEmitter.off(event, handler);
|
|
}
|
|
|
|
public offInit(event: string, handler: InitHandler): void {
|
|
this.initEmitter.off(event, handler);
|
|
}
|
|
|
|
public offAll(): void {
|
|
this.filterEmitter.removeAllListeners();
|
|
this.actionEmitter.removeAllListeners();
|
|
this.initEmitter.removeAllListeners();
|
|
}
|
|
}
|
|
|
|
const emitter = new Emitter();
|
|
|
|
export default emitter;
|