Convert gr-js-api-interface from element to class

Change-Id: Ib0fa07484fb36db969f6f69c77598643cd0a0b6a
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
index 2a607a7..8a3e47f 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
@@ -19,7 +19,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-dropdown-list/gr-dropdown-list';
 import '../../shared/gr-icons/gr-icons';
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import '../../shared/gr-page-nav/gr-page-nav';
 import '../gr-admin-group-list/gr-admin-group-list';
 import '../gr-group/gr-group';
@@ -63,18 +62,11 @@
 } from '../../../types/common';
 import {GroupNameChangedDetail} from '../gr-group/gr-group';
 import {ValueChangeDetail} from '../../shared/gr-dropdown-list/gr-dropdown-list';
-import {GrJsApiInterface} from '../../shared/gr-js-api-interface/gr-js-api-interface-element';
 import {appContext} from '../../../services/app-context';
 import {GerritView} from '../../../services/router/router-model';
 
 const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/;
 
-export interface GrAdminView {
-  $: {
-    jsAPI: GrJsApiInterface;
-  };
-}
-
 interface AdminSubsectionLink {
   text: string;
   value: string;
@@ -183,6 +175,8 @@
 
   private restApiService = appContext.restApiService;
 
+  private readonly jsAPI = appContext.jsApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -218,7 +212,7 @@
             }
             return capabilities;
           }),
-        () => this.$.jsAPI.getAdminMenuLinks(),
+        () => this.jsAPI.getAdminMenuLinks(),
         options
       ).then(res => {
         this._filteredLinks = res.links;
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_html.ts b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_html.ts
index 9db5691..f073a9f 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_html.ts
@@ -178,5 +178,4 @@
       <gr-repo-dashboards repo="[[params.repo]]"></gr-repo-dashboards>
     </div>
   </template>
-  <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js
index 33ad694..e813bec 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js
@@ -128,7 +128,7 @@
 
   test('_filteredLinks from plugin', () => {
     stubRestApi('getAccount').returns(Promise.resolve(undefined));
-    sinon.stub(element.$.jsAPI, 'getAdminMenuLinks').returns([
+    sinon.stub(element.jsAPI, 'getAdminMenuLinks').returns([
       {text: 'internal link text', url: '/internal/link/url'},
       {text: 'external link text', url: 'http://external/link/url'},
     ]);
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index f3c701f..78c48f8 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -19,7 +19,6 @@
 import '../../shared/gr-dialog/gr-dialog';
 import '../../shared/gr-dropdown/gr-dropdown';
 import '../../shared/gr-icons/gr-icons';
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import '../../shared/gr-overlay/gr-overlay';
 import '../gr-confirm-abandon-dialog/gr-confirm-abandon-dialog';
 import '../gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog';
@@ -56,7 +55,6 @@
   TargetElement,
 } from '../../plugins/gr-plugin-types';
 import {customElement, observe, property} from '@polymer/decorators';
-import {GrJsApiInterface} from '../../shared/gr-js-api-interface/gr-js-api-interface-element';
 import {
   ActionPriority,
   ActionType,
@@ -322,7 +320,6 @@
 
 export interface GrChangeActions {
   $: {
-    jsAPI: GrJsApiInterface;
     mainContent: Element;
     overlay: GrOverlay;
     confirmRebase: GrConfirmRebaseDialog;
@@ -383,6 +380,8 @@
 
   reporting = appContext.reportingService;
 
+  private readonly jsAPI = appContext.jsApiService;
+
   @property({type: Object})
   change?: ChangeViewChangeInfo;
 
@@ -567,7 +566,7 @@
   /** @override */
   ready() {
     super.ready();
-    this.$.jsAPI.addElement(TargetElement.CHANGE_ACTIONS, this);
+    this.jsAPI.addElement(TargetElement.CHANGE_ACTIONS, this);
     this.restApiService.getConfig().then(config => {
       this._config = config;
     });
@@ -635,7 +634,7 @@
     change: ChangeInfo;
     revisionActions: ActionNameToActionInfoMap;
   }) {
-    this.$.jsAPI.handleEvent(PluginEventType.SHOW_REVISION_ACTIONS, detail);
+    this.jsAPI.handleEvent(PluginEventType.SHOW_REVISION_ACTIONS, detail);
   }
 
   @observe('change')
@@ -1142,7 +1141,7 @@
     if (!this.change) {
       return false;
     }
-    return this.$.jsAPI.canSubmitChange(
+    return this.jsAPI.canSubmitChange(
       this.change,
       this._getRevision(this.change, this.latestPatchNum)
     );
@@ -1607,7 +1606,7 @@
   // TODO(rmistry): Redo this after
   // https://bugs.chromium.org/p/gerrit/issues/detail?id=4671 is resolved.
   _setReviewOnRevert(newChangeId: NumericChangeId) {
-    const review = this.$.jsAPI.getReviewPostRevert(this.change);
+    const review = this.jsAPI.getReviewPostRevert(this.change);
     if (!review) {
       return Promise.resolve(undefined);
     }
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
index 0a3e536..2bbfbbf 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
@@ -269,5 +269,4 @@
       </div>
     </gr-dialog>
   </gr-overlay>
-  <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js
index b58519b..6c9a27d 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js
@@ -467,7 +467,7 @@
     test('_setReviewOnRevert', () => {
       const review = {labels: {'Foo': 1, 'Bar-Baz': -2}};
       const changeId = 1234;
-      sinon.stub(element.$.jsAPI, 'getReviewPostRevert').returns(review);
+      sinon.stub(element.jsAPI, 'getReviewPostRevert').returns(review);
       const saveStub = stubRestApi('saveChangeReview')
           .returns(Promise.resolve());
       return element._setReviewOnRevert(changeId).then(() => {
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 90ecc10..faba2e9 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -25,7 +25,6 @@
 import '../../shared/gr-change-status/gr-change-status';
 import '../../shared/gr-date-formatter/gr-date-formatter';
 import '../../shared/gr-editable-content/gr-editable-content';
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import '../../shared/gr-linked-text/gr-linked-text';
 import '../../shared/gr-overlay/gr-overlay';
 import '../../shared/gr-tooltip-content/gr-tooltip-content';
@@ -77,7 +76,6 @@
 import {changeStatuses, changeStatusString} from '../../../utils/change-util';
 import {EventType as PluginEventType} from '../../plugins/gr-plugin-types';
 import {customElement, property, observe} from '@polymer/decorators';
-import {GrJsApiInterface} from '../../shared/gr-js-api-interface/gr-js-api-interface-element';
 import {GrApplyFixDialog} from '../../diff/gr-apply-fix-dialog/gr-apply-fix-dialog';
 import {GrFileListHeader} from '../gr-file-list-header/gr-file-list-header';
 import {GrEditableContent} from '../../shared/gr-editable-content/gr-editable-content';
@@ -207,7 +205,6 @@
 
 export interface GrChangeView {
   $: {
-    jsAPI: GrJsApiInterface;
     commentAPI: GrCommentApi;
     applyFixDialog: GrApplyFixDialog;
     fileList: GrFileList & Element;
@@ -266,6 +263,8 @@
 
   flagsService = appContext.flagsService;
 
+  readonly jsAPI = appContext.jsApiService;
+
   /**
    * URL params passed from the router.
    */
@@ -868,7 +867,7 @@
     // Trim trailing whitespace from each line.
     const message = e.detail.content.replace(TRAILING_WHITESPACE_REGEX, '');
 
-    this.$.jsAPI.handleCommitMessage(this._change, message);
+    this.jsAPI.handleCommitMessage(this._change, message);
 
     this.$.commitMessageEditor.disabled = true;
     this.restApiService
@@ -1351,7 +1350,7 @@
   _sendShowChangeEvent() {
     if (!this._patchRange)
       throw new Error('missing required _patchRange property');
-    this.$.jsAPI.handleEvent(PluginEventType.SHOW_CHANGE, {
+    this.jsAPI.handleEvent(PluginEventType.SHOW_CHANGE, {
       change: this._change,
       patchNum: this._patchRange.patchNum,
       info: {mergeable: this._mergeable},
@@ -1875,7 +1874,7 @@
         changeRecord.path
       );
     }
-    this.$.jsAPI.handleEvent(PluginEventType.LABEL_CHANGE, {
+    this.jsAPI.handleEvent(PluginEventType.LABEL_CHANGE, {
       change: this._change,
     });
   }
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
index 6001aa4..66a8793 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
@@ -865,6 +865,5 @@
     >
     </gr-reply-dialog>
   </gr-overlay>
-  <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
   <gr-comment-api id="commentAPI"></gr-comment-api>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index 4d50c001..d986e99 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -2740,7 +2740,7 @@
     element._change = {...change};
     element._patchRange = {patchNum: 4 as PatchSetNum};
     element._mergeable = true;
-    const showStub = sinon.stub(element.$.jsAPI, 'handleEvent');
+    const showStub = sinon.stub(element.jsAPI, 'handleEvent');
     element._sendShowChangeEvent();
     assert.isTrue(showStub.calledOnce);
     assert.equal(showStub.lastCall.args[0], EventType.SHOW_CHANGE);
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
index 3facde1..e10b12b 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
@@ -17,15 +17,14 @@
 import '../../shared/gr-dialog/gr-dialog';
 import '../../../styles/shared-styles';
 import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-revert-dialog_html';
 import {customElement, property} from '@polymer/decorators';
-import {JsApiService} from '../../shared/gr-js-api-interface/gr-js-api-types';
 import {ChangeInfo, CommitId} from '../../../types/common';
 import {fireAlert} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const ERR_COMMIT_NOT_FOUND = 'Unable to find the commit hash of this change.';
 const CHANGE_SUBJECT_LIMIT = 50;
@@ -41,11 +40,6 @@
   message?: string;
 }
 
-export interface GrConfirmRevertDialog {
-  $: {
-    jsAPI: JsApiService & Element;
-  };
-}
 @customElement('gr-confirm-revert-dialog')
 export class GrConfirmRevertDialog extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -93,6 +87,8 @@
   @property({type: Array})
   _revertMessages: string[] = [];
 
+  private readonly jsAPI = appContext.jsApiService;
+
   _computeIfSingleRevert(revertType: number) {
     return revertType === RevertType.REVERT_SINGLE_CHANGE;
   }
@@ -102,7 +98,7 @@
   }
 
   _modifyRevertMsg(change: ChangeInfo, commitMessage: string, message: string) {
-    return this.$.jsAPI.modifyRevertMsg(change, message, commitMessage);
+    return this.jsAPI.modifyRevertMsg(change, message, commitMessage);
   }
 
   populate(change: ChangeInfo, commitMessage: string, changes: ChangeInfo[]) {
@@ -152,7 +148,7 @@
     msg: string,
     commitMessage: string
   ) {
-    return this.$.jsAPI.modifyRevertSubmissionMsg(change, msg, commitMessage);
+    return this.jsAPI.modifyRevertSubmissionMsg(change, msg, commitMessage);
   }
 
   _populateRevertSubmissionMessage(
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts
index f5561fc..a4e3e96 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts
@@ -100,5 +100,4 @@
       </gr-endpoint-decorator>
     </div>
   </gr-dialog>
-  <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts
index ac52664..9e1256f 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts
@@ -16,24 +16,18 @@
  */
 import '../../shared/gr-dialog/gr-dialog';
 import '../../../styles/shared-styles';
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-revert-submission-dialog_html';
 import {customElement, property} from '@polymer/decorators';
-import {JsApiService} from '../../shared/gr-js-api-interface/gr-js-api-types';
 import {ChangeInfo} from '../../../types/common';
 import {fireAlert} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const ERR_COMMIT_NOT_FOUND = 'Unable to find the commit hash of this change.';
 const CHANGE_SUBJECT_LIMIT = 50;
 
-export interface GrConfirmRevertSubmissionDialog {
-  $: {
-    jsAPI: JsApiService & Element;
-  };
-}
 @customElement('gr-confirm-revert-submission-dialog')
 export class GrConfirmRevertSubmissionDialog extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -60,6 +54,8 @@
   @property({type: String})
   commitMessage?: string;
 
+  private readonly jsAPI = appContext.jsApiService;
+
   _getTrimmedChangeSubject(subject: string) {
     if (!subject) return '';
     if (subject.length < CHANGE_SUBJECT_LIMIT) return subject;
@@ -70,7 +66,7 @@
     if (!change || !this.message || !this.commitMessage) {
       return this.message;
     }
-    return this.$.jsAPI.modifyRevertSubmissionMsg(
+    return this.jsAPI.modifyRevertSubmissionMsg(
       change,
       this.message,
       this.commitMessage
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts
index cae4e1f..49a9c70 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts
@@ -57,5 +57,4 @@
       ></iron-autogrow-textarea>
     </div>
   </gr-dialog>
-  <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index 253b5ff..c856f68 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -20,7 +20,6 @@
 import '../../shared/gr-textarea/gr-textarea';
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-formatted-text/gr-formatted-text';
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import '../../shared/gr-overlay/gr-overlay';
 import '../../shared/gr-storage/gr-storage';
 import '../../shared/gr-account-list/gr-account-list';
@@ -59,7 +58,6 @@
   GroupObjectInput,
   RawAccountInput,
 } from '../../shared/gr-account-list/gr-account-list';
-import {JsApiService} from '../../shared/gr-js-api-interface/gr-js-api-types';
 import {
   AccountId,
   AccountInfo,
@@ -160,7 +158,6 @@
 
 export interface GrReplyDialog {
   $: {
-    jsAPI: JsApiService & Element;
     reviewers: GrAccountList;
     ccs: GrAccountList;
     cancelButton: GrButton;
@@ -377,6 +374,8 @@
 
   private readonly storage = new GrStorage();
 
+  private readonly jsAPI = appContext.jsApiService;
+
   get keyBindings() {
     return {
       esc: '_handleEscKey',
@@ -423,7 +422,7 @@
   /** @override */
   ready() {
     super.ready();
-    this.$.jsAPI.addElement(TargetElement.REPLY_DIALOG, this);
+    this.jsAPI.addElement(TargetElement.REPLY_DIALOG, this);
   }
 
   open(focusTarget?: FocusTarget) {
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
index 5409243..22f81c9 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
@@ -612,5 +612,4 @@
       </section>
     </div>
   </div>
-  <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
index 8e5a2b3..71d92d0 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
@@ -19,7 +19,6 @@
 import '../gr-error-dialog/gr-error-dialog';
 import '../../shared/gr-alert/gr-alert';
 import '../../shared/gr-overlay/gr-overlay';
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
index c91c82e..b43b3b0 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
@@ -17,7 +17,6 @@
 import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
 import '../../shared/gr-dropdown/gr-dropdown';
 import '../../shared/gr-icons/gr-icons';
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import '../gr-account-dropdown/gr-account-dropdown';
 import '../gr-smart-search/gr-smart-search';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
@@ -35,7 +34,6 @@
   TopMenuEntryInfo,
   TopMenuItemInfo,
 } from '../../../types/common';
-import {JsApiService} from '../../shared/gr-js-api-interface/gr-js-api-types';
 import {AuthType} from '../../../constants/constants';
 import {DropdownLink} from '../../shared/gr-dropdown/gr-dropdown';
 import {appContext} from '../../../services/app-context';
@@ -102,12 +100,6 @@
   AuthType.CUSTOM_EXTENSION,
 ]);
 
-export interface GrMainHeader {
-  $: {
-    jsAPI: JsApiService & Element;
-  };
-}
-
 @customElement('gr-main-header')
 export class GrMainHeader extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -164,6 +156,8 @@
 
   private readonly restApiService = appContext.restApiService;
 
+  private readonly jsAPI = appContext.jsApiService;
+
   /** @override */
   ready() {
     super.ready();
@@ -296,7 +290,7 @@
             }
             return capabilities;
           }),
-        () => this.$.jsAPI.getAdminMenuLinks()
+        () => this.jsAPI.getAdminMenuLinks()
       ).then(res => {
         this._adminLinks = res.links;
       });
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
index c674f96..e8a1512 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
@@ -252,5 +252,4 @@
       </div>
     </div>
   </nav>
-  <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
index 6112831..eaa9029 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../shared/gr-comment-thread/gr-comment-thread';
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import '../gr-diff/gr-diff';
 import '../gr-syntax-layer/gr-syntax-layer';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
@@ -60,7 +59,6 @@
   DiffPreferencesInfo,
   IgnoreWhitespaceType,
 } from '../../../types/diff';
-import {JsApiService} from '../../shared/gr-js-api-interface/gr-js-api-types';
 import {GrDiff, LineOfInterest} from '../gr-diff/gr-diff';
 import {GrSyntaxLayer} from '../gr-syntax-layer/gr-syntax-layer';
 import {DiffViewMode, Side, CommentSide} from '../../../constants/constants';
@@ -115,7 +113,6 @@
 
 export interface GrDiffHost {
   $: {
-    jsAPI: JsApiService & Element;
     syntaxLayer: GrSyntaxLayer & Element;
     diff: GrDiff;
   };
@@ -267,6 +264,8 @@
 
   private readonly restApiService = appContext.restApiService;
 
+  private readonly jsAPI = appContext.jsApiService;
+
   /** @override */
   created() {
     super.created();
@@ -399,7 +398,7 @@
 
   private _getLayers(path: string, changeNum: NumericChangeId): DiffLayer[] {
     // Get layers from plugins (if any).
-    return [this.$.syntaxLayer, ...this.$.jsAPI.getDiffLayers(path, changeNum)];
+    return [this.$.syntaxLayer, ...this.jsAPI.getDiffLayers(path, changeNum)];
   }
 
   private _onRenderOnce(): Promise<CustomEvent> {
@@ -413,7 +412,7 @@
   }
 
   clear() {
-    if (this.path) this.$.jsAPI.disposeDiffLayers(this.path);
+    if (this.path) this.jsAPI.disposeDiffLayers(this.path);
     this._layers = [];
   }
 
@@ -432,7 +431,7 @@
 
     const basePatchNum = toNumberOnly(this.patchRange.basePatchNum);
     const patchNum = toNumberOnly(this.patchRange.patchNum);
-    this.$.jsAPI
+    this.jsAPI
       .getCoverageAnnotationApis()
       .then(coverageAnnotationApis => {
         coverageAnnotationApis.forEach(coverageAnnotationApi => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts
index 48b82ec..a7eebf4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts
@@ -49,5 +49,4 @@
     enabled="[[_syntaxHighlightingEnabled]]"
     diff="[[diff]]"
   ></gr-syntax-layer>
-  <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
index 0c1a92d..536cf26 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
@@ -47,10 +47,8 @@
   suite('plugin layers', () => {
     const pluginLayers = [{annotate: () => {}}, {annotate: () => {}}];
     setup(() => {
-      stub('gr-js-api-interface', {
-        getDiffLayers() { return pluginLayers; },
-      });
       element = basicFixture.instantiate();
+      sinon.stub(element.jsAPI, 'getDiffLayers').returns(pluginLayers);
       element.changeNum = 123;
       element.path = 'some/path';
     });
@@ -59,7 +57,7 @@
       element.change = createChange();
       stubRestApi('getDiff').returns(Promise.resolve({content: []}));
       await element.reload();
-      assert(element.$.jsAPI.getDiffLayers.called);
+      assert(element.jsAPI.getDiffLayers.called);
     });
   });
 
@@ -1330,17 +1328,14 @@
       coverageProviderStub = sinon.stub().returns(
           Promise.resolve(exampleRanges));
 
-      stub('gr-js-api-interface', {
-        getCoverageAnnotationApis() {
-          return Promise.resolve([{
+      element = basicFixture.instantiate();
+      sinon.stub(element.jsAPI, 'getCoverageAnnotationApis').returns(
+          Promise.resolve([{
             notify: notifyStub,
             getCoverageProvider() {
               return coverageProviderStub;
             },
-          }]);
-        },
-      });
-      element = basicFixture.instantiate();
+          }]));
       element.changeNum = 123;
       element.change = createChange();
       element.path = 'some/path';
@@ -1362,7 +1357,7 @@
 
     test('getCoverageAnnotationApis should be called', async () => {
       await element.reload();
-      assert.isTrue(element.$.jsAPI.getCoverageAnnotationApis.calledOnce);
+      assert.isTrue(element.jsAPI.getCoverageAnnotationApis.calledOnce);
     });
 
     test('coverageRangeChanged should be called', async () => {
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
index 716cd67..12863fd 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts
index 02786dd..dc3ebcf 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import {updateStyles} from '@polymer/polymer/lib/mixins/element-mixin';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
index ed84406..81b3a16 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import '../../shared/gr-js-api-interface/gr-js-api-interface';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
index ca40b42..9d7e19b 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/shared-styles';
-import '../gr-js-api-interface/gr-js-api-interface';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts
index 2c1d87e..9ae2900 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts
@@ -18,9 +18,9 @@
   ActionType,
   ActionPriority,
 } from '../../../services/gr-rest-api/gr-rest-api';
-import {JsApiService} from './gr-js-api-types';
 import {PluginApi, TargetElement} from '../../plugins/gr-plugin-types';
 import {ActionInfo, RequireProperties} from '../../../types/common';
+import {appContext} from '../../../services/app-context';
 
 export enum ChangeActions {
   ABANDON = 'abandon',
@@ -119,9 +119,7 @@
    */
   private ensureEl(): GrChangeActionsElement {
     if (!this._el) {
-      const sharedApiElement = (document.createElement(
-        'gr-js-api-interface'
-      ) as unknown) as JsApiService;
+      const sharedApiElement = appContext.jsApiService;
       this.setEl(
         (sharedApiElement.getElement(
           TargetElement.CHANGE_ACTIONS
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.js
index 77eb457..608e711 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.js
@@ -16,13 +16,11 @@
  */
 
 import '../../../test/common-test-setup-karma.js';
-import './gr-js-api-interface.js';
 import {getPluginLoader} from './gr-plugin-loader.js';
 import {resetPlugins} from '../../../test/test-utils.js';
 import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
 import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-js-api-interface');
+import {appContext} from '../../../services/app-context.js';
 
 const pluginApi = _testOnly_initGerritPluginApi();
 
@@ -36,7 +34,7 @@
 
     stubRestApi('getAccount').returns(Promise.resolve({name: 'Judy Hopps'}));
     stubRestApi('send').returns(Promise.resolve({status: 200}));
-    element = basicFixture.instantiate();
+    element = appContext.jsApiService;
   });
 
   teardown(() => {
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
index 1d54896..412165d 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
@@ -14,12 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {getPluginLoader} from './gr-plugin-loader';
-
-import {customElement} from '@polymer/decorators';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {
   ChangeInfo,
@@ -42,10 +37,7 @@
 const elements: {[key: string]: HTMLElement} = {};
 const eventCallbacks: {[key: string]: EventCallback[]} = {};
 
-@customElement('gr-js-api-interface')
-export class GrJsApiInterface
-  extends GestureEventListeners(LegacyElementMixin(PolymerElement))
-  implements JsApiService {
+export class GrJsApiInterface implements JsApiService {
   private readonly reporting = appContext.reportingService;
 
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -330,9 +322,3 @@
     return eventCallbacks[type] || [];
   }
 }
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-js-api-interface': JsApiService & Element;
-  }
-}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
index d5d734a..47b6006 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
@@ -26,12 +26,11 @@
 import {stubBaseUrl} from '../../../test/test-utils.js';
 import sinon from 'sinon/pkg/sinon-esm';
 import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-js-api-interface');
+import {appContext} from '../../../services/app-context.js';
 
 const pluginApi = _testOnly_initGerritPluginApi();
 
-suite('gr-js-api-interface tests', () => {
+suite('GrJsApiInterface tests', () => {
   let element;
   let plugin;
   let errorStub;
@@ -51,7 +50,7 @@
     getResponseObjectStub = stubRestApi('getResponseObject').returns(
         Promise.resolve());
     sendStub = stubRestApi('send').returns(Promise.resolve({status: 200}));
-    element = basicFixture.instantiate();
+    element = appContext.jsApiService;
     errorStub = sinon.stub(element.reporting, 'error');
     pluginApi.install(p => { plugin = p; }, '0.1',
         'http://test.com/plugins/testplugin/static/test.js');
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
index 0a49b97..37db662 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
@@ -14,9 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {ActionInfo, ChangeInfo, PatchSetNum} from '../../../types/common';
+import {
+  ActionInfo,
+  ChangeInfo,
+  PatchSetNum,
+  ReviewInput,
+  RevisionInfo,
+} from '../../../types/common';
 import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
-import {DiffLayer} from '../../../types/types';
+import {DiffLayer, ParsedChangeInfo} from '../../../types/types';
 import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
 import {MenuLink} from '../../plugins/gr-admin-api/gr-admin-api';
 
@@ -54,5 +60,7 @@
   disposeDiffLayers(path: string): void;
   getCoverageAnnotationApis(): Promise<GrAnnotationActionsInterface[]>;
   getAdminMenuLinks(): MenuLink[];
-  // TODO(TS): Add more methods when needed for the TS conversion.
+  handleCommitMessage(change: ChangeInfo | ParsedChangeInfo, msg: string): void;
+  canSubmitChange(change: ChangeInfo, revision?: RevisionInfo | null): boolean;
+  getReviewPostRevert(change?: ChangeInfo): ReviewInput;
 }
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.js
index 19762e0..6b62291 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.js
@@ -16,7 +16,6 @@
  */
 
 import '../../../test/common-test-setup-karma.js';
-import './gr-js-api-interface.js';
 import {PRELOADED_PROTOCOL, PLUGIN_LOADING_TIMEOUT_MS} from './gr-api-utils.js';
 import {_testOnly_resetPluginLoader} from './gr-plugin-loader.js';
 import {resetPlugins, stubBaseUrl} from '../../../test/test-utils.js';
@@ -24,8 +23,6 @@
 import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
 import {addListenerForTest, stubRestApi} from '../../../test/test-utils.js';
 
-const basicFixture = fixtureFromElement('gr-js-api-interface');
-
 const pluginApi = _testOnly_initGerritPluginApi();
 
 suite('gr-plugin-loader tests', () => {
@@ -42,7 +39,6 @@
     stubRestApi('send').returns(Promise.resolve({status: 200}));
     pluginLoader = _testOnly_resetPluginLoader();
     sinon.stub(document.body, 'appendChild');
-    basicFixture.instantiate();
     url = window.location.origin;
   });
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
index bc720c8..f21ddc6 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
@@ -16,7 +16,6 @@
  */
 
 import {getBaseUrl} from '../../../utils/url-util';
-import {getSharedApiEl} from '../../../utils/dom-util';
 import {GrAttributeHelper} from '../../plugins/gr-attribute-helper/gr-attribute-helper';
 import {GrChangeActionsInterface} from './gr-change-actions-js-api';
 import {GrChangeReplyInterface} from './gr-change-reply-js-api';
@@ -44,7 +43,6 @@
 } from '../../plugins/gr-plugin-types';
 import {RequestPayload} from '../../../types/common';
 import {HttpMethod} from '../../../constants/constants';
-import {JsApiService} from './gr-js-api-types';
 import {GrChangeActions} from '../../change/gr-change-actions/gr-change-actions';
 import {GrChecksApi} from '../../plugins/gr-checks-api/gr-checks-api';
 import {appContext} from '../../../services/app-context';
@@ -76,11 +74,9 @@
 
   private readonly _name: string = PLUGIN_NAME_NOT_SET;
 
-  // TODO(TS): Change type to GrJsApiInterface
-  private readonly sharedApiElement: JsApiService;
+  private readonly jsApi = appContext.jsApiService;
 
   constructor(url?: string) {
-    this.sharedApiElement = getSharedApiEl();
     this._domHooks = new GrDomHooksManager(this);
 
     if (!url) {
@@ -174,7 +170,7 @@
 
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   on(eventName: EventType, callback: (...args: any[]) => any) {
-    this.sharedApiElement.addEventCallback(eventName, callback);
+    this.jsApi.addEventCallback(eventName, callback);
   }
 
   url(path?: string) {
@@ -243,14 +239,14 @@
   changeActions() {
     return new GrChangeActionsInterface(
       this,
-      (this.sharedApiElement.getElement(
+      (this.jsApi.getElement(
         TargetElement.CHANGE_ACTIONS
       ) as unknown) as GrChangeActions
     );
   }
 
   changeReply() {
-    return new GrChangeReplyInterface(this, this.sharedApiElement);
+    return new GrChangeReplyInterface(this, this.jsApi);
   }
 
   checks(): GrChecksApi {
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
index ea0ad4e..329cc7e 100644
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
+++ b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
@@ -17,7 +17,7 @@
 import '../gr-js-api-interface/gr-js-api-interface';
 import {EventType} from '../../plugins/gr-plugin-types';
 import {HighlightJS} from '../../../types/types';
-import {GrJsApiInterface} from '../gr-js-api-interface/gr-js-api-interface-element';
+import {appContext} from '../../../services/app-context';
 
 // preloaded in PolyGerritIndexHtml.soy
 const HLJS_PATH = 'bower_components/highlightjs/highlight.min.js';
@@ -31,7 +31,7 @@
 }
 
 export class GrLibLoader {
-  private readonly jsAPI = new GrJsApiInterface();
+  private readonly jsAPI = appContext.jsApiService;
 
   _hljsState: HljsState = {
     configured: false,
diff --git a/polygerrit-ui/app/services/app-context-init.ts b/polygerrit-ui/app/services/app-context-init.ts
index 5c5a37c..09e0724 100644
--- a/polygerrit-ui/app/services/app-context-init.ts
+++ b/polygerrit-ui/app/services/app-context-init.ts
@@ -22,6 +22,7 @@
 import {GrRestApiInterface} from '../elements/shared/gr-rest-api-interface/gr-rest-api-interface';
 import {ChangeService} from './change/change-service';
 import {ChecksService} from './checks/checks-service';
+import {GrJsApiInterface} from '../elements/shared/gr-js-api-interface/gr-js-api-interface-element';
 
 type ServiceName = keyof AppContext;
 type ServiceCreator<T> = () => T;
@@ -71,5 +72,6 @@
     restApiService: () => new GrRestApiInterface(appContext.authService),
     changeService: () => new ChangeService(appContext.restApiService),
     checksService: () => new ChecksService(),
+    jsApiService: () => new GrJsApiInterface(),
   });
 }
diff --git a/polygerrit-ui/app/services/app-context.ts b/polygerrit-ui/app/services/app-context.ts
index e740cfd..1f618fd 100644
--- a/polygerrit-ui/app/services/app-context.ts
+++ b/polygerrit-ui/app/services/app-context.ts
@@ -21,6 +21,7 @@
 import {RestApiService} from './gr-rest-api/gr-rest-api';
 import {ChangeService} from './change/change-service';
 import {ChecksService} from './checks/checks-service';
+import {JsApiService} from '../elements/shared/gr-js-api-interface/gr-js-api-types';
 
 export interface AppContext {
   flagsService: FlagsService;
@@ -30,6 +31,7 @@
   restApiService: RestApiService;
   changeService: ChangeService;
   checksService: ChecksService;
+  jsApiService: JsApiService;
 }
 
 /**
diff --git a/polygerrit-ui/app/services/gr-event-interface/gr-event-interface_test.js b/polygerrit-ui/app/services/gr-event-interface/gr-event-interface_test.js
index 32590e0..6ce5eea 100644
--- a/polygerrit-ui/app/services/gr-event-interface/gr-event-interface_test.js
+++ b/polygerrit-ui/app/services/gr-event-interface/gr-event-interface_test.js
@@ -16,11 +16,8 @@
  */
 
 import '../../test/common-test-setup-karma.js';
-import '../../elements/shared/gr-js-api-interface/gr-js-api-interface.js';
 import {EventEmitter} from './gr-event-interface_impl.js';
 
-const basicFixture = fixtureFromElement('gr-js-api-interface');
-
 suite('gr-event-interface tests', () => {
   let gerrit;
   setup(() => {
@@ -29,7 +26,6 @@
 
   suite('test on Gerrit', () => {
     setup(() => {
-      basicFixture.instantiate();
       gerrit.removeAllListeners();
     });
 
diff --git a/polygerrit-ui/app/utils/dom-util.ts b/polygerrit-ui/app/utils/dom-util.ts
index ca5de4d..c9a7d6b 100644
--- a/polygerrit-ui/app/utils/dom-util.ts
+++ b/polygerrit-ui/app/utils/dom-util.ts
@@ -16,7 +16,6 @@
  */
 
 import {EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {JsApiService} from '../elements/shared/gr-js-api-interface/gr-js-api-types';
 
 /**
  * Event emitted from polymer elements.
@@ -217,24 +216,6 @@
   return `${prefix}${str.replace(/[^a-zA-Z0-9-_]/g, '_')}`;
 }
 
-// shared API element
-// TODO: Make this a proper service singleton. Move into AppContext?
-let _sharedApiEl: JsApiService;
-
-/**
- * Retrieves the shared API element.
- * We want to keep a single instance of API element instead of
- * creating multiple elements.
- */
-export function getSharedApiEl(): JsApiService {
-  if (!_sharedApiEl) {
-    _sharedApiEl = (document.createElement(
-      'gr-js-api-interface'
-    ) as unknown) as JsApiService;
-  }
-  return _sharedApiEl;
-}
-
 // document.activeElement is not enough, because it's not getting activeElement
 // without looking inside of shadow roots. This will find best activeElement.
 export function findActiveElement(