inbox.dog 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -0
- package/dist/index.cjs +130 -0
- package/dist/index.d.cts +80 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +103 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# inbox.dog
|
|
2
|
+
|
|
3
|
+
Gmail OAuth tokens in 3 API calls. No Google Cloud console required.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
npm install inbox.dog
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { InboxDog } from "inbox.dog";
|
|
13
|
+
|
|
14
|
+
const dog = new InboxDog();
|
|
15
|
+
|
|
16
|
+
// 1. Create an API key (one-time)
|
|
17
|
+
const key = await dog.createKey("my-app");
|
|
18
|
+
// → { client_id, client_secret, name, credits: 10 }
|
|
19
|
+
|
|
20
|
+
// 2. Redirect user to Gmail consent
|
|
21
|
+
const url = dog.getAuthUrl({
|
|
22
|
+
clientId: key.client_id,
|
|
23
|
+
redirectUri: "http://localhost:3000/callback",
|
|
24
|
+
scope: "email",
|
|
25
|
+
});
|
|
26
|
+
// → redirect user to `url`
|
|
27
|
+
|
|
28
|
+
// 3. Exchange the code from callback for tokens
|
|
29
|
+
const tokens = await dog.exchangeCode(code, key.client_id, key.client_secret);
|
|
30
|
+
// → { access_token, refresh_token, email, expires_in }
|
|
31
|
+
|
|
32
|
+
// Use tokens directly with Gmail API
|
|
33
|
+
const res = await fetch("https://gmail.googleapis.com/gmail/v1/users/me/messages", {
|
|
34
|
+
headers: { Authorization: `Bearer ${tokens.access_token}` },
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## API
|
|
39
|
+
|
|
40
|
+
### `new InboxDog(options?)`
|
|
41
|
+
|
|
42
|
+
| Option | Type | Default |
|
|
43
|
+
|-----------|------------|-----------------------|
|
|
44
|
+
| `baseUrl` | `string` | `https://inbox.dog` |
|
|
45
|
+
| `fetch` | `Function` | `globalThis.fetch` |
|
|
46
|
+
|
|
47
|
+
### `createKey(name?): Promise<CreateKeyResponse>`
|
|
48
|
+
|
|
49
|
+
Create a new API key. Returns `{ client_id, client_secret, name, credits }`.
|
|
50
|
+
|
|
51
|
+
### `getKey(clientId, clientSecret): Promise<KeyInfo>`
|
|
52
|
+
|
|
53
|
+
Get key info. Returns `{ client_id, name, credits, created_at }`.
|
|
54
|
+
|
|
55
|
+
### `getAuthUrl(opts): string`
|
|
56
|
+
|
|
57
|
+
Build the OAuth authorization URL. No network request.
|
|
58
|
+
|
|
59
|
+
| Param | Type | Required |
|
|
60
|
+
|---------------|----------|----------|
|
|
61
|
+
| `clientId` | `string` | yes |
|
|
62
|
+
| `redirectUri` | `string` | yes |
|
|
63
|
+
| `scope` | `Scope` | no |
|
|
64
|
+
| `state` | `string` | no |
|
|
65
|
+
|
|
66
|
+
Scopes: `"email"` (default, read-only), `"email:read"`, `"email:send"`, `"email:full"`.
|
|
67
|
+
|
|
68
|
+
### `exchangeCode(code, clientId, clientSecret): Promise<TokenResponse>`
|
|
69
|
+
|
|
70
|
+
Exchange auth code for tokens. Costs 1 credit.
|
|
71
|
+
|
|
72
|
+
Returns `{ access_token, refresh_token, token_type, expires_in, email }`.
|
|
73
|
+
|
|
74
|
+
### `refreshToken(refreshToken, clientId, clientSecret): Promise<RefreshResponse>`
|
|
75
|
+
|
|
76
|
+
Refresh an expired access token. Free.
|
|
77
|
+
|
|
78
|
+
Returns `{ access_token, token_type, expires_in }`.
|
|
79
|
+
|
|
80
|
+
### `checkout(clientId, clientSecret, credits?): Promise<CheckoutResponse>`
|
|
81
|
+
|
|
82
|
+
Create a Stripe checkout session. Returns `{ checkout_url, session_id }`.
|
|
83
|
+
|
|
84
|
+
## Errors
|
|
85
|
+
|
|
86
|
+
All errors throw `InboxDogError` with these properties:
|
|
87
|
+
|
|
88
|
+
| Property | Type | Description |
|
|
89
|
+
|-----------|----------|------------------------|
|
|
90
|
+
| `code` | `string` | Machine-readable code |
|
|
91
|
+
| `status` | `number` | HTTP status code |
|
|
92
|
+
| `message` | `string` | Human-readable message |
|
|
93
|
+
| `action` | `string` | Suggested fix |
|
|
94
|
+
| `docs` | `string` | Link to docs |
|
|
95
|
+
|
|
96
|
+
Error codes: `INVALID_CREDENTIALS` (401), `INSUFFICIENT_CREDITS` (402), `VALIDATION_ERROR` (400), `STATE_NOT_FOUND` (400), `AUTH_CODE_NOT_FOUND` (400), `TOKEN_EXCHANGE_FAILED` (500).
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
try {
|
|
100
|
+
await dog.exchangeCode(code, clientId, clientSecret);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
if (e instanceof InboxDogError && e.code === "INSUFFICIENT_CREDITS") {
|
|
103
|
+
const { checkout_url } = await dog.checkout(clientId, clientSecret);
|
|
104
|
+
// redirect user to checkout_url
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Links
|
|
110
|
+
|
|
111
|
+
- Docs: https://inbox.dog/docs
|
|
112
|
+
- API Reference: https://inbox.dog/docs/api
|
|
113
|
+
- GitHub: https://github.com/acoyfellow/inbox.dog
|
|
114
|
+
- MCP Server: `npx @inboxdog/mcp-server`
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
InboxDog: () => InboxDog,
|
|
24
|
+
InboxDogError: () => InboxDogError,
|
|
25
|
+
createClient: () => createClient,
|
|
26
|
+
default: () => index_default
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
var DEFAULT_BASE_URL = "https://inbox.dog";
|
|
30
|
+
var InboxDogError = class extends Error {
|
|
31
|
+
constructor(status, detail) {
|
|
32
|
+
super(detail.message);
|
|
33
|
+
this.name = "InboxDogError";
|
|
34
|
+
this.code = detail.code;
|
|
35
|
+
this.status = status;
|
|
36
|
+
this.action = detail.action;
|
|
37
|
+
this.docs = detail.docs;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var InboxDog = class {
|
|
41
|
+
constructor(opts = {}) {
|
|
42
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
43
|
+
this.fetchFn = opts.fetch ?? globalThis.fetch;
|
|
44
|
+
}
|
|
45
|
+
// ── API Keys ───────────────────────────────────────
|
|
46
|
+
/** Create a new API key. Returns client_id, client_secret, and 10 free credits. */
|
|
47
|
+
async createKey(name) {
|
|
48
|
+
return this.post("/api/keys", { name: name ?? "default" });
|
|
49
|
+
}
|
|
50
|
+
/** Get API key info (credits remaining, creation date). */
|
|
51
|
+
async getKey(clientId, clientSecret) {
|
|
52
|
+
return this.request(`/api/keys/${clientId}`, {
|
|
53
|
+
headers: { "X-Client-Secret": clientSecret }
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
// ── OAuth ──────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Build the authorization URL to redirect users to.
|
|
59
|
+
* This is a pure URL builder — no network request.
|
|
60
|
+
*/
|
|
61
|
+
getAuthUrl(opts) {
|
|
62
|
+
const url = new URL(`${this.baseUrl}/oauth/authorize`);
|
|
63
|
+
url.searchParams.set("client_id", opts.clientId);
|
|
64
|
+
url.searchParams.set("redirect_uri", opts.redirectUri);
|
|
65
|
+
if (opts.scope) url.searchParams.set("scope", opts.scope);
|
|
66
|
+
if (opts.state) url.searchParams.set("state", opts.state);
|
|
67
|
+
return url.toString();
|
|
68
|
+
}
|
|
69
|
+
/** Exchange an authorization code for access + refresh tokens. Costs 1 credit. */
|
|
70
|
+
async exchangeCode(code, clientId, clientSecret) {
|
|
71
|
+
return this.post("/oauth/token", {
|
|
72
|
+
code,
|
|
73
|
+
client_id: clientId,
|
|
74
|
+
client_secret: clientSecret
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Refresh an expired access token. Free, no credit cost. */
|
|
78
|
+
async refreshToken(refreshToken, clientId, clientSecret) {
|
|
79
|
+
return this.post("/oauth/token", {
|
|
80
|
+
grant_type: "refresh_token",
|
|
81
|
+
refresh_token: refreshToken,
|
|
82
|
+
client_id: clientId,
|
|
83
|
+
client_secret: clientSecret
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// ── Billing ────────────────────────────────────────
|
|
87
|
+
/** Create a Stripe checkout session to purchase credits. */
|
|
88
|
+
async checkout(clientId, clientSecret, credits) {
|
|
89
|
+
return this.post("/api/checkout", {
|
|
90
|
+
client_id: clientId,
|
|
91
|
+
client_secret: clientSecret,
|
|
92
|
+
credits: credits ?? 100
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// ── Internal ───────────────────────────────────────
|
|
96
|
+
async request(path, init = {}) {
|
|
97
|
+
const res = await this.fetchFn(`${this.baseUrl}${path}`, {
|
|
98
|
+
...init,
|
|
99
|
+
headers: {
|
|
100
|
+
"Content-Type": "application/json",
|
|
101
|
+
...init.headers
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
const body = await res.json();
|
|
105
|
+
if (!res.ok) {
|
|
106
|
+
const err = body;
|
|
107
|
+
throw new InboxDogError(res.status, err.error ?? {
|
|
108
|
+
code: "UNKNOWN",
|
|
109
|
+
message: `HTTP ${res.status}`
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return body;
|
|
113
|
+
}
|
|
114
|
+
async post(path, data) {
|
|
115
|
+
return this.request(path, {
|
|
116
|
+
method: "POST",
|
|
117
|
+
body: JSON.stringify(data)
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
function createClient(opts) {
|
|
122
|
+
return new InboxDog(opts);
|
|
123
|
+
}
|
|
124
|
+
var index_default = InboxDog;
|
|
125
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
126
|
+
0 && (module.exports = {
|
|
127
|
+
InboxDog,
|
|
128
|
+
InboxDogError,
|
|
129
|
+
createClient
|
|
130
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** inbox.dog — Gmail OAuth tokens in 3 API calls */
|
|
2
|
+
type Scope = "email" | "email:read" | "email:send" | "email:full";
|
|
3
|
+
interface CreateKeyResponse {
|
|
4
|
+
client_id: string;
|
|
5
|
+
client_secret: string;
|
|
6
|
+
name: string;
|
|
7
|
+
credits: number;
|
|
8
|
+
}
|
|
9
|
+
interface KeyInfo {
|
|
10
|
+
client_id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
credits: number;
|
|
13
|
+
created_at: number;
|
|
14
|
+
}
|
|
15
|
+
interface TokenResponse {
|
|
16
|
+
access_token: string;
|
|
17
|
+
refresh_token: string;
|
|
18
|
+
token_type: "Bearer";
|
|
19
|
+
expires_in: number;
|
|
20
|
+
email: string;
|
|
21
|
+
}
|
|
22
|
+
interface RefreshResponse {
|
|
23
|
+
access_token: string;
|
|
24
|
+
token_type: "Bearer";
|
|
25
|
+
expires_in: number;
|
|
26
|
+
}
|
|
27
|
+
interface CheckoutResponse {
|
|
28
|
+
checkout_url: string;
|
|
29
|
+
session_id: string;
|
|
30
|
+
}
|
|
31
|
+
interface InboxDogErrorDetail {
|
|
32
|
+
code: string;
|
|
33
|
+
message: string;
|
|
34
|
+
action?: string;
|
|
35
|
+
docs?: string;
|
|
36
|
+
}
|
|
37
|
+
declare class InboxDogError extends Error {
|
|
38
|
+
readonly code: string;
|
|
39
|
+
readonly status: number;
|
|
40
|
+
readonly action?: string;
|
|
41
|
+
readonly docs?: string;
|
|
42
|
+
constructor(status: number, detail: InboxDogErrorDetail);
|
|
43
|
+
}
|
|
44
|
+
interface InboxDogOptions {
|
|
45
|
+
/** Override the base URL (default: https://inbox.dog) */
|
|
46
|
+
baseUrl?: string;
|
|
47
|
+
/** Provide a custom fetch implementation */
|
|
48
|
+
fetch?: typeof globalThis.fetch;
|
|
49
|
+
}
|
|
50
|
+
declare class InboxDog {
|
|
51
|
+
private baseUrl;
|
|
52
|
+
private fetchFn;
|
|
53
|
+
constructor(opts?: InboxDogOptions);
|
|
54
|
+
/** Create a new API key. Returns client_id, client_secret, and 10 free credits. */
|
|
55
|
+
createKey(name?: string): Promise<CreateKeyResponse>;
|
|
56
|
+
/** Get API key info (credits remaining, creation date). */
|
|
57
|
+
getKey(clientId: string, clientSecret: string): Promise<KeyInfo>;
|
|
58
|
+
/**
|
|
59
|
+
* Build the authorization URL to redirect users to.
|
|
60
|
+
* This is a pure URL builder — no network request.
|
|
61
|
+
*/
|
|
62
|
+
getAuthUrl(opts: {
|
|
63
|
+
clientId: string;
|
|
64
|
+
redirectUri: string;
|
|
65
|
+
scope?: Scope;
|
|
66
|
+
state?: string;
|
|
67
|
+
}): string;
|
|
68
|
+
/** Exchange an authorization code for access + refresh tokens. Costs 1 credit. */
|
|
69
|
+
exchangeCode(code: string, clientId: string, clientSecret: string): Promise<TokenResponse>;
|
|
70
|
+
/** Refresh an expired access token. Free, no credit cost. */
|
|
71
|
+
refreshToken(refreshToken: string, clientId: string, clientSecret: string): Promise<RefreshResponse>;
|
|
72
|
+
/** Create a Stripe checkout session to purchase credits. */
|
|
73
|
+
checkout(clientId: string, clientSecret: string, credits?: number): Promise<CheckoutResponse>;
|
|
74
|
+
private request;
|
|
75
|
+
private post;
|
|
76
|
+
}
|
|
77
|
+
/** Create an InboxDog client with default options. */
|
|
78
|
+
declare function createClient(opts?: InboxDogOptions): InboxDog;
|
|
79
|
+
|
|
80
|
+
export { type CheckoutResponse, type CreateKeyResponse, InboxDog, InboxDogError, type InboxDogErrorDetail, type InboxDogOptions, type KeyInfo, type RefreshResponse, type Scope, type TokenResponse, createClient, InboxDog as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** inbox.dog — Gmail OAuth tokens in 3 API calls */
|
|
2
|
+
type Scope = "email" | "email:read" | "email:send" | "email:full";
|
|
3
|
+
interface CreateKeyResponse {
|
|
4
|
+
client_id: string;
|
|
5
|
+
client_secret: string;
|
|
6
|
+
name: string;
|
|
7
|
+
credits: number;
|
|
8
|
+
}
|
|
9
|
+
interface KeyInfo {
|
|
10
|
+
client_id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
credits: number;
|
|
13
|
+
created_at: number;
|
|
14
|
+
}
|
|
15
|
+
interface TokenResponse {
|
|
16
|
+
access_token: string;
|
|
17
|
+
refresh_token: string;
|
|
18
|
+
token_type: "Bearer";
|
|
19
|
+
expires_in: number;
|
|
20
|
+
email: string;
|
|
21
|
+
}
|
|
22
|
+
interface RefreshResponse {
|
|
23
|
+
access_token: string;
|
|
24
|
+
token_type: "Bearer";
|
|
25
|
+
expires_in: number;
|
|
26
|
+
}
|
|
27
|
+
interface CheckoutResponse {
|
|
28
|
+
checkout_url: string;
|
|
29
|
+
session_id: string;
|
|
30
|
+
}
|
|
31
|
+
interface InboxDogErrorDetail {
|
|
32
|
+
code: string;
|
|
33
|
+
message: string;
|
|
34
|
+
action?: string;
|
|
35
|
+
docs?: string;
|
|
36
|
+
}
|
|
37
|
+
declare class InboxDogError extends Error {
|
|
38
|
+
readonly code: string;
|
|
39
|
+
readonly status: number;
|
|
40
|
+
readonly action?: string;
|
|
41
|
+
readonly docs?: string;
|
|
42
|
+
constructor(status: number, detail: InboxDogErrorDetail);
|
|
43
|
+
}
|
|
44
|
+
interface InboxDogOptions {
|
|
45
|
+
/** Override the base URL (default: https://inbox.dog) */
|
|
46
|
+
baseUrl?: string;
|
|
47
|
+
/** Provide a custom fetch implementation */
|
|
48
|
+
fetch?: typeof globalThis.fetch;
|
|
49
|
+
}
|
|
50
|
+
declare class InboxDog {
|
|
51
|
+
private baseUrl;
|
|
52
|
+
private fetchFn;
|
|
53
|
+
constructor(opts?: InboxDogOptions);
|
|
54
|
+
/** Create a new API key. Returns client_id, client_secret, and 10 free credits. */
|
|
55
|
+
createKey(name?: string): Promise<CreateKeyResponse>;
|
|
56
|
+
/** Get API key info (credits remaining, creation date). */
|
|
57
|
+
getKey(clientId: string, clientSecret: string): Promise<KeyInfo>;
|
|
58
|
+
/**
|
|
59
|
+
* Build the authorization URL to redirect users to.
|
|
60
|
+
* This is a pure URL builder — no network request.
|
|
61
|
+
*/
|
|
62
|
+
getAuthUrl(opts: {
|
|
63
|
+
clientId: string;
|
|
64
|
+
redirectUri: string;
|
|
65
|
+
scope?: Scope;
|
|
66
|
+
state?: string;
|
|
67
|
+
}): string;
|
|
68
|
+
/** Exchange an authorization code for access + refresh tokens. Costs 1 credit. */
|
|
69
|
+
exchangeCode(code: string, clientId: string, clientSecret: string): Promise<TokenResponse>;
|
|
70
|
+
/** Refresh an expired access token. Free, no credit cost. */
|
|
71
|
+
refreshToken(refreshToken: string, clientId: string, clientSecret: string): Promise<RefreshResponse>;
|
|
72
|
+
/** Create a Stripe checkout session to purchase credits. */
|
|
73
|
+
checkout(clientId: string, clientSecret: string, credits?: number): Promise<CheckoutResponse>;
|
|
74
|
+
private request;
|
|
75
|
+
private post;
|
|
76
|
+
}
|
|
77
|
+
/** Create an InboxDog client with default options. */
|
|
78
|
+
declare function createClient(opts?: InboxDogOptions): InboxDog;
|
|
79
|
+
|
|
80
|
+
export { type CheckoutResponse, type CreateKeyResponse, InboxDog, InboxDogError, type InboxDogErrorDetail, type InboxDogOptions, type KeyInfo, type RefreshResponse, type Scope, type TokenResponse, createClient, InboxDog as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var DEFAULT_BASE_URL = "https://inbox.dog";
|
|
3
|
+
var InboxDogError = class extends Error {
|
|
4
|
+
constructor(status, detail) {
|
|
5
|
+
super(detail.message);
|
|
6
|
+
this.name = "InboxDogError";
|
|
7
|
+
this.code = detail.code;
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.action = detail.action;
|
|
10
|
+
this.docs = detail.docs;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var InboxDog = class {
|
|
14
|
+
constructor(opts = {}) {
|
|
15
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
16
|
+
this.fetchFn = opts.fetch ?? globalThis.fetch;
|
|
17
|
+
}
|
|
18
|
+
// ── API Keys ───────────────────────────────────────
|
|
19
|
+
/** Create a new API key. Returns client_id, client_secret, and 10 free credits. */
|
|
20
|
+
async createKey(name) {
|
|
21
|
+
return this.post("/api/keys", { name: name ?? "default" });
|
|
22
|
+
}
|
|
23
|
+
/** Get API key info (credits remaining, creation date). */
|
|
24
|
+
async getKey(clientId, clientSecret) {
|
|
25
|
+
return this.request(`/api/keys/${clientId}`, {
|
|
26
|
+
headers: { "X-Client-Secret": clientSecret }
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
// ── OAuth ──────────────────────────────────────────
|
|
30
|
+
/**
|
|
31
|
+
* Build the authorization URL to redirect users to.
|
|
32
|
+
* This is a pure URL builder — no network request.
|
|
33
|
+
*/
|
|
34
|
+
getAuthUrl(opts) {
|
|
35
|
+
const url = new URL(`${this.baseUrl}/oauth/authorize`);
|
|
36
|
+
url.searchParams.set("client_id", opts.clientId);
|
|
37
|
+
url.searchParams.set("redirect_uri", opts.redirectUri);
|
|
38
|
+
if (opts.scope) url.searchParams.set("scope", opts.scope);
|
|
39
|
+
if (opts.state) url.searchParams.set("state", opts.state);
|
|
40
|
+
return url.toString();
|
|
41
|
+
}
|
|
42
|
+
/** Exchange an authorization code for access + refresh tokens. Costs 1 credit. */
|
|
43
|
+
async exchangeCode(code, clientId, clientSecret) {
|
|
44
|
+
return this.post("/oauth/token", {
|
|
45
|
+
code,
|
|
46
|
+
client_id: clientId,
|
|
47
|
+
client_secret: clientSecret
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** Refresh an expired access token. Free, no credit cost. */
|
|
51
|
+
async refreshToken(refreshToken, clientId, clientSecret) {
|
|
52
|
+
return this.post("/oauth/token", {
|
|
53
|
+
grant_type: "refresh_token",
|
|
54
|
+
refresh_token: refreshToken,
|
|
55
|
+
client_id: clientId,
|
|
56
|
+
client_secret: clientSecret
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// ── Billing ────────────────────────────────────────
|
|
60
|
+
/** Create a Stripe checkout session to purchase credits. */
|
|
61
|
+
async checkout(clientId, clientSecret, credits) {
|
|
62
|
+
return this.post("/api/checkout", {
|
|
63
|
+
client_id: clientId,
|
|
64
|
+
client_secret: clientSecret,
|
|
65
|
+
credits: credits ?? 100
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
// ── Internal ───────────────────────────────────────
|
|
69
|
+
async request(path, init = {}) {
|
|
70
|
+
const res = await this.fetchFn(`${this.baseUrl}${path}`, {
|
|
71
|
+
...init,
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
...init.headers
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
const body = await res.json();
|
|
78
|
+
if (!res.ok) {
|
|
79
|
+
const err = body;
|
|
80
|
+
throw new InboxDogError(res.status, err.error ?? {
|
|
81
|
+
code: "UNKNOWN",
|
|
82
|
+
message: `HTTP ${res.status}`
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return body;
|
|
86
|
+
}
|
|
87
|
+
async post(path, data) {
|
|
88
|
+
return this.request(path, {
|
|
89
|
+
method: "POST",
|
|
90
|
+
body: JSON.stringify(data)
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
function createClient(opts) {
|
|
95
|
+
return new InboxDog(opts);
|
|
96
|
+
}
|
|
97
|
+
var index_default = InboxDog;
|
|
98
|
+
export {
|
|
99
|
+
InboxDog,
|
|
100
|
+
InboxDogError,
|
|
101
|
+
createClient,
|
|
102
|
+
index_default as default
|
|
103
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "inbox.dog",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Gmail OAuth tokens in 3 API calls. No Google Cloud console required.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"test": "echo 'No tests yet'",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"gmail",
|
|
31
|
+
"oauth",
|
|
32
|
+
"email",
|
|
33
|
+
"google",
|
|
34
|
+
"oauth2",
|
|
35
|
+
"api",
|
|
36
|
+
"tokens"
|
|
37
|
+
],
|
|
38
|
+
"author": "acoyfellow",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/acoyfellow/inbox.dog",
|
|
43
|
+
"directory": "package"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://inbox.dog",
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"tsup": "^8.0.0",
|
|
48
|
+
"typescript": "^5.5.0"
|
|
49
|
+
}
|
|
50
|
+
}
|