Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ember-simple-auth): implement internal EventTarget #2887

Merged
merged 1 commit into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading