Skip to content

Commit

Permalink
Merge pull request #2887 from mainmatter/implement-our-event-target
Browse files Browse the repository at this point in the history
feat(ember-simple-auth): implement internal EventTarget
  • Loading branch information
BobrImperator authored Dec 28, 2024
2 parents 3b0986c + f5c3b6e commit 414c082
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 119 deletions.
4 changes: 1 addition & 3 deletions packages/ember-simple-auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@
"prettier": "3.3.3",
"rollup": "4.25.0",
"rollup-plugin-copy": "3.5.0",
"typescript": "^5.7.2",
"typescript-event-target": "^1.1.1"
"typescript": "^5.7.2"
},
"publishConfig": {
"registry": "https://registry.npmjs.org"
Expand All @@ -79,7 +78,6 @@
"./initializers/ember-simple-auth.js": "./dist/_app_/initializers/ember-simple-auth.js",
"./services/session.js": "./dist/_app_/services/session.js",
"./session-stores/application.js": "./dist/_app_/session-stores/application.js",
"./utils/inject.js": "./dist/_app_/utils/inject.js",
"./utils/is-fastboot.js": "./dist/_app_/utils/is-fastboot.js",
"./utils/location.js": "./dist/_app_/utils/location.js",
"./utils/objects-are-equal.js": "./dist/_app_/utils/objects-are-equal.js"
Expand Down
42 changes: 42 additions & 0 deletions packages/ember-simple-auth/src/-internals/event-target.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import EmberObject from '@ember/object';
import Evented from '@ember/object/evented';

export type EventListener<Events, Event extends keyof Events> = (event: Events[Event]) => void;

type ValueIsEvent<T> = {
[key in keyof T]: CustomEvent;
};

/**
* This module exists to act as a 'shim' between Native EventTarget API, which unfortunately can't be used due to Fastboot's node environment not providing it.
*
* It more-or-less implements the same API as an EventTarget would have but on top of Evented mixin instead.
*/
export default class EsaEventTarget<Events extends ValueIsEvent<Events>> extends EmberObject.extend(
Evented
) {
addEventListener<Event extends keyof Events & string>(
event: Event,
cb: EventListener<Events, Event>
) {
(this as any).on(event, cb);
}

removeEventListener<Event extends keyof Events & string>(
event: Event,
cb: EventListener<Events, Event>
) {
(this as any).off(event, cb);
}

dispatchEvent<Event extends keyof Events & string>(event: Event, value: Events[Event]['detail']) {
// let customEvent: CustomEvent;
// if (value) {
// customEvent = new CustomEvent(event, { detail: value });
// } else {
// customEvent = new CustomEvent(event);
// }

(this as any).trigger(event, { detail: value });
}
}
21 changes: 7 additions & 14 deletions packages/ember-simple-auth/src/authenticators/base.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import EmberObject from '@ember/object';
import { TypedEventTarget, type TypedEventListener } from 'typescript-event-target';
import EsaEventTarget, { type EventListener } from '../-internals/event-target';

export interface AuthenticatorEvents {
sessionDataUpdated: CustomEvent<any>;
sessionDataInvalidated: CustomEvent;
}

class AuthenticatorEventTarget extends TypedEventTarget<AuthenticatorEvents> {}
class AuthenticatorEventTarget extends EsaEventTarget<AuthenticatorEvents> {}

/**
The base class for all authenticators. __This serves as a starting point for
Expand Down Expand Up @@ -175,29 +175,22 @@ export default class EsaBaseAuthenticator extends EmberObject {

on<Event extends keyof AuthenticatorEvents>(
event: Event,
cb: TypedEventListener<AuthenticatorEvents, Event>
cb: EventListener<AuthenticatorEvents, Event>
) {
this.authenticatorEvents.addEventListener(event, cb);
this.authenticatorEvents.addEventListener(event, cb as any);
}

off<Event extends keyof AuthenticatorEvents>(
event: Event,
cb: TypedEventListener<AuthenticatorEvents, Event>
cb: EventListener<AuthenticatorEvents, Event>
) {
this.authenticatorEvents.removeEventListener(event, cb);
this.authenticatorEvents.removeEventListener(event, cb as any);
}

trigger<Event extends keyof AuthenticatorEvents>(
event: Event,
value: AuthenticatorEvents[Event]['detail']
) {
let customEvent;
if (value) {
customEvent = new CustomEvent(event, { detail: value });
} else {
customEvent = new CustomEvent(event);
}

this.authenticatorEvents.dispatchTypedEvent(event, customEvent);
this.authenticatorEvents.dispatchEvent(event, value);
}
}
28 changes: 11 additions & 17 deletions packages/ember-simple-auth/src/internal-session.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { isEmpty, isNone } from '@ember/utils';
import ObjectProxy from '@ember/object/proxy';
import { set } from '@ember/object';
import { action, set } from '@ember/object';
import { debug, assert } from '@ember/debug';
import { getOwner, setOwner } from '@ember/application';
import { isTesting } from '@embroider/macros';
import EsaEventTarget from './-internals/event-target';

class SessionEventTarget extends EventTarget {}
class SessionEventTarget extends EsaEventTarget {}

/**
__An internal implementation of Session. Communicates with stores and emits events.__
Expand Down Expand Up @@ -97,7 +98,7 @@ export default ObjectProxy.extend({
let authenticator = this._lookupAuthenticator(this.authenticator);
return authenticator.invalidate(this.content.authenticated, ...arguments).then(
() => {
authenticator.off('sessionDataUpdated', this._onSessionDataUpdated.bind(this));
authenticator.off('sessionDataUpdated', this._onSessionDataUpdated);
this._busy = false;
return this._clear(true);
},
Expand Down Expand Up @@ -217,17 +218,17 @@ export default ObjectProxy.extend({

_bindToAuthenticatorEvents() {
const authenticator = this._lookupAuthenticator(this.authenticator);
authenticator.on('sessionDataUpdated', this._onSessionDataUpdated.bind(this));
authenticator.on('sessionDataInvalidated', this._onSessionDataInvalidated.bind(this));
authenticator.on('sessionDataUpdated', this._onSessionDataUpdated);
authenticator.on('sessionDataInvalidated', this._onSessionDataInvalidated);
},

_onSessionDataUpdated({ detail: content }) {
_onSessionDataUpdated: action(function ({ detail: content }) {
this._setup(this.authenticator, content);
},
}),

_onSessionDataInvalidated() {
_onSessionDataInvalidated: action(function () {
this._clear(true);
},
}),

_bindToStoreEvents() {
this.store.on('sessionDataUpdated', ({ detail: content }) => {
Expand Down Expand Up @@ -282,13 +283,6 @@ export default ObjectProxy.extend({
},

trigger(event, value) {
let customEvent;
if (value) {
customEvent = new CustomEvent(event, { detail: value });
} else {
customEvent = new CustomEvent(event);
}

this.sessionEvents.dispatchEvent(customEvent);
this.sessionEvents.dispatchEvent(event, value);
},
});
23 changes: 5 additions & 18 deletions packages/ember-simple-auth/src/session-stores/base.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import EmberObject from '@ember/object';
import { TypedEventTarget, type TypedEventListener } from 'typescript-event-target';
import EsaEventTarget, { type EventListener } from '../-internals/event-target';

export interface SessionEvents {
sessionDataUpdated: CustomEvent<any>;
}

class SessionStoreEventTarget extends TypedEventTarget<SessionEvents> {}
class SessionStoreEventTarget extends EsaEventTarget<SessionEvents> {}

/**
The base class for all session stores. __This serves as a starting point for
Expand Down Expand Up @@ -79,28 +79,15 @@ export default class EsaBaseSessionStore extends EmberObject {
return Promise.reject();
}

on<Event extends keyof SessionEvents>(
event: Event,
cb: TypedEventListener<SessionEvents, Event>
) {
on<Event extends keyof SessionEvents>(event: Event, cb: EventListener<SessionEvents, Event>) {
this.sessionStoreEvents.addEventListener(event, cb);
}

off<Event extends keyof SessionEvents>(
event: Event,
cb: TypedEventListener<SessionEvents, Event>
) {
off<Event extends keyof SessionEvents>(event: Event, cb: EventListener<SessionEvents, Event>) {
this.sessionStoreEvents.removeEventListener(event, cb);
}

trigger<Event extends keyof SessionEvents>(event: Event, value: SessionEvents[Event]['detail']) {
let customEvent;
if (value) {
customEvent = new CustomEvent(event, { detail: value });
} else {
customEvent = new CustomEvent(event);
}

this.sessionStoreEvents.dispatchTypedEvent(event, customEvent);
this.sessionStoreEvents.dispatchEvent(event, value);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { bind } from '@ember/runloop';
import { getOwner } from '@ember/application';
import BaseStore from './base';
import objectsAreEqual from '../utils/objects-are-equal';
import isFastBoot from '../utils/is-fastboot';
import { action } from '@ember/object';

/**
Session store that persists data in the browser's `localStorage`.
Expand Down Expand Up @@ -35,7 +35,6 @@ export default class LocalStorageStore extends BaseStore {
key = 'ember_simple_auth-session';

_isFastBoot: boolean = false;
_boundHandler: (e: any) => void;
_lastData: Record<string, string> | null = null;

constructor(owner: any) {
Expand All @@ -44,15 +43,14 @@ export default class LocalStorageStore extends BaseStore {
this._isFastBoot = this.hasOwnProperty('_isFastBoot')
? this._isFastBoot
: isFastBoot(getOwner(this));
this._boundHandler = bind(this, this._handleStorageEvent);
if (!this.get('_isFastBoot')) {
window.addEventListener('storage', this._boundHandler);
window.addEventListener('storage', this._handleStorageEvent);
}
}

willDestroy() {
if (!this.get('_isFastBoot')) {
window.removeEventListener('storage', this._boundHandler);
window.removeEventListener('storage', this._handleStorageEvent);
}
}

Expand Down Expand Up @@ -104,6 +102,7 @@ export default class LocalStorageStore extends BaseStore {
return Promise.resolve();
}

@action
_handleStorageEvent(e: StorageEvent) {
if (e.key === this.get('key')) {
this.restore().then(data => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { bind } from '@ember/runloop';
import { getOwner } from '@ember/application';
import BaseStore from './base';
import objectsAreEqual from '../utils/objects-are-equal';
import isFastBoot from '../utils/is-fastboot';
import { action } from '@ember/object';

/**
Session store that persists data in the browser's `sessionStorage`.
Expand Down Expand Up @@ -30,7 +30,6 @@ export default class SessionStorageStore extends BaseStore {
*/
key = 'ember_simple_auth-session';
_isFastBoot: boolean = false;
_boundHandler: (e: any) => void;
_lastData: Record<string, string> | null = null;

constructor(owner: any) {
Expand All @@ -39,15 +38,14 @@ export default class SessionStorageStore extends BaseStore {
this._isFastBoot = this.hasOwnProperty('_isFastBoot')
? this._isFastBoot
: isFastBoot(getOwner(this));
this._boundHandler = bind(this, this._handleStorageEvent);
if (!this.get('_isFastBoot')) {
window.addEventListener('storage', this._boundHandler);
window.addEventListener('storage', this._handleStorageEvent);
}
}

willDestroy() {
if (!this.get('_isFastBoot')) {
window.removeEventListener('storage', bind(this, this._handleStorageEvent));
window.removeEventListener('storage', this._handleStorageEvent);
}
}

Expand Down Expand Up @@ -99,6 +97,7 @@ export default class SessionStorageStore extends BaseStore {
return Promise.resolve();
}

@action
_handleStorageEvent(e: StorageEvent) {
if (e.key === this.get('key')) {
this.restore().then(data => {
Expand Down
2 changes: 1 addition & 1 deletion packages/test-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"ember-maybe-import-regenerator": "1.0.0",
"ember-qunit": "7.0.0",
"ember-resolver": "11.0.1",
"ember-simple-auth": "6.1.0",
"ember-simple-auth": "workspace:*",
"ember-source": "5.12.0",
"ember-source-channel-url": "3.0.0",
"ember-try": "3.0.0",
Expand Down
Loading

0 comments on commit 414c082

Please sign in to comment.