Repository: octokit/oauth-app.js (ts)

Issue:
OAuthApp.defaults()
**What’s missing?**

Compare https://github.com/octokit/core.js#defaults

```js
const MyOAuthApp = OAuthApp.defaults({
  /* set default constructor options */
})
```

**Why?**

Needed for the `octokit` module, see https://github.com/octokit/octokit.js/pull/15. The `Octokit` constructor needs to be set to `Octokit` exported by the `octokit` module, which includes several plugins.

**Alternatives you tried**

I could implement the defaults functionality within `octokit` but there it's the same amount of work, and `OAuthApp.defaults()` will be useful outside of `octokit`

Pull request description:
feat: `OAuthApp.defaults()`
fixes #209


Patch:
diff --git a/README.md b/README.md
index bafa80e..cd74b57 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@
   - [For OAuth Apps](#for-oauth-apps)
   - [For GitHub Apps](#for-github-apps)
 - [Examples](#examples)
+- [`OAuthApp.defaults(options)`](#oauthappdefaultsoptions)
 - [Constructor options](#constructor-options)
 - [`app.on(eventName, eventHandler)`](#apponeventname-eventhandler)
 - [`app.octokit`](#appoctokit)
@@ -112,6 +113,18 @@ require("http").createServer(createNodeMiddleware(app)).listen(3000);
 - Serverless functions, hosted on [Zeit's now](https://zeit.co/): <https://github.com/gr2m/octokit-oauth-app-now-example>
 - Serverless functions, hosted on AWS (via [begin.com](https://begin.com/)): <https://github.com/gr2m/octokit-oauth-app-begin-example/>
 
+## `OAuthApp.defaults(options)`
+
+Create a new `OAuthApp` with custom defaults for the [constructor options](#constructor-options)
+
+```js
+const MyOAuthApp = OAuthApp.defaults({
+  Octokit: MyOctokit,
+});
+const app = new MyOAuthApp({ clientId, clientSecret });
+// app.octokit is now an instance of MyOctokit
+```
+
 ## Constructor options
 
 <table width="100%">
diff --git a/src/index.ts b/src/index.ts
index 38779ad..7b1552e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -50,9 +50,27 @@ import {
 } from "./types";
 export { createNodeMiddleware } from "./middleware/node/index";
 
+type Constructor<T> = new (...args: any[]) => T;
+
 export class OAuthApp<TClientType extends ClientType = "oauth-app"> {
   static VERSION = VERSION;
 
+  static defaults<TClientType extends ClientType, S extends Constructor<any>>(
+    this: S,
+    defaults: Partial<ConstructorOptions<TClientType>>
+  ) {
+    const OAuthAppWithDefaults = class extends this {
+      constructor(...args: any[]) {
+        super({
+          ...defaults,
+          ...args[0],
+        });
+      }
+    };
+
+    return OAuthAppWithDefaults;
+  }
+
   constructor(options: ConstructorOptions<TClientType>) {
     const Octokit = options.Octokit || OAuthAppOctokit;
     this.type = (options.clientType || "oauth-app") as TClientType;


Test patch:
diff --git a/test/app.test.ts b/test/app.test.ts
index ed9d912..a275027 100644
--- a/test/app.test.ts
+++ b/test/app.test.ts
@@ -4,6 +4,32 @@ import { Octokit } from "@octokit/core";
 import { OAuthApp } from "../src";
 import { OAuthAppOctokit } from "../src/oauth-app-octokit";
 
+describe("OAuthApp.defaultst", () => {
+  test("sets default options", () => {
+    const MyOAuthApp = OAuthApp.defaults({
+      allowSignup: false,
+    });
+
+    const app = new MyOAuthApp({
+      clientId: "1234567890abcdef1234",
+      clientSecret: "1234567890abcdef1234567890abcdef12345678",
+    });
+
+    const result = app.getWebFlowAuthorizationUrl({ state: "test" });
+    expect(result).toMatchInlineSnapshot(`
+      Object {
+        "allowSignup": false,
+        "clientId": "1234567890abcdef1234",
+        "clientType": "oauth-app",
+        "login": null,
+        "redirectUrl": null,
+        "scopes": Array [],
+        "state": "test",
+        "url": "https://github.com/login/oauth/authorize?allow_signup=false&client_id=1234567890abcdef1234&state=test",
+      }
+    `);
+  });
+});
 describe("app", () => {
   it("app.getUserOctokit(options)", async () => {
     const mock = fetchMock
diff --git a/test/smoke.test.ts b/test/smoke.test.ts
index 218d58c..2cb6c4e 100644
--- a/test/smoke.test.ts
+++ b/test/smoke.test.ts
@@ -1,10 +1,14 @@
 import { OAuthApp } from "../src";
 
 describe("Smoke test", () => {
-  it("is a function", () => {
+  it("OAuthApp is a function", () => {
     expect(OAuthApp).toBeInstanceOf(Function);
   });
 
+  it("OAuthApp.defaults is a function", () => {
+    expect(OAuthApp.defaults).toBeInstanceOf(Function);
+  });
+
   it("OAuthApp.VERSION is set", () => {
     expect(OAuthApp.VERSION).toEqual("0.0.0-development");
   });