@inboxlink/sdk 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/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/index.d.ts +177 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +279 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Etienne Fokou
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# `@inboxlink/sdk`
|
|
2
|
+
|
|
3
|
+
Host-app HTTP client for [InboxLink](https://github.com/EtienneFokou-E18560/inboxlink).
|
|
4
|
+
|
|
5
|
+
Gmail-first surface: Connect sessions, grant exchange, **list / get messages**, and **history sync**. Do **not** ship `INBOXLINK_API_SECRET` to browsers. This package does **not** add Microsoft Graph or IMAP client APIs.
|
|
6
|
+
|
|
7
|
+
**Hosts never set `GOOGLE_*`.** Google OAuth lives on the InboxLink server (Production or your self-host). Your app only needs a redirect URI you control plus (optionally) an API secret when the server is in `multi` mode.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# After a public npm release (maintainer runs the publish workflow):
|
|
13
|
+
npm install @inboxlink/sdk
|
|
14
|
+
|
|
15
|
+
# Until then — monorepo / git dependency:
|
|
16
|
+
pnpm add @inboxlink/sdk --filter your-app
|
|
17
|
+
# or: "file:../inboxlink/packages/sdk" / git+https://github.com/EtienneFokou-E18560/inboxlink.git
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Until the first npm publish, consume the package from this repository via the pnpm workspace or a git dependency. See [docs/publishing.md](../../docs/publishing.md).
|
|
21
|
+
|
|
22
|
+
## Quick start (Production, single mode)
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { InboxLink, InboxLinkApiError } from "@inboxlink/sdk";
|
|
26
|
+
|
|
27
|
+
// baseUrl defaults to https://inboxlink-two.vercel.app
|
|
28
|
+
// apiSecret omitted — Production currently runs INBOXLINK_MODE=single
|
|
29
|
+
const il = new InboxLink();
|
|
30
|
+
|
|
31
|
+
const session = await il.createConnectSession({
|
|
32
|
+
externalUserId: "user-1",
|
|
33
|
+
redirectUri: "http://127.0.0.1:9999/done", // your host callback, not Google
|
|
34
|
+
});
|
|
35
|
+
// Redirect the end user to session.connectUrl
|
|
36
|
+
|
|
37
|
+
// On your redirect handler:
|
|
38
|
+
const { grantId } = await il.completeConnect({ redirectUrl: request.url });
|
|
39
|
+
const page = await il.messages.list(grantId, { limit: 20 });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Local / multi-mode overrides
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const il = new InboxLink({
|
|
46
|
+
baseUrl: process.env.INBOXLINK_BASE_URL ?? "http://localhost:8787",
|
|
47
|
+
apiSecret: process.env.INBOXLINK_API_SECRET, // required when server is multi
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Client surface (v0.1, Gmail)
|
|
52
|
+
|
|
53
|
+
| Area | Methods | HTTP |
|
|
54
|
+
|------|---------|------|
|
|
55
|
+
| Connect | `createConnectSession`, `completeConnect` | sessions + exchange |
|
|
56
|
+
| Helpers | `parseConnectRedirect`, `connectUrlForToken`, `INBOXLINK_PRODUCTION_URL` | local |
|
|
57
|
+
| Link | `link.createSession` | `POST /v1/link/sessions` |
|
|
58
|
+
| Grants | `grants.exchange`, `grants.list`, `grants.revoke`, `grants.sync` | `/v1/grants…` |
|
|
59
|
+
| Messages | `messages.list`, `messages.get`, `messages.iterate` | `/v1/grants/:id/messages…` |
|
|
60
|
+
| Webhooks | `webhooks.verify` | local HMAC check |
|
|
61
|
+
|
|
62
|
+
- `messages.list` → live Gmail list
|
|
63
|
+
- `messages.get` → `{ message }` including optional attachment metadata (`id`, `filename`, `mimeType`, `size`) — not bytes
|
|
64
|
+
- `grants.sync` → inline Gmail history sync (`bootstrap` / `incremental` / `full`)
|
|
65
|
+
|
|
66
|
+
## Host env (few knobs)
|
|
67
|
+
|
|
68
|
+
See [`examples/host-integration/host.env.example`](../../examples/host-integration/host.env.example). Do **not** copy server `.env.example` into a host app — that file includes Postgres, vault, and Google OAuth for **InboxLink operators**, not hosts.
|
|
69
|
+
|
|
70
|
+
## Versioning
|
|
71
|
+
|
|
72
|
+
- **0.x** — public API may still change; treat minors as potentially breaking for host apps.
|
|
73
|
+
- Publish only via the manual GitHub Actions workflow (see [docs/publishing.md](../../docs/publishing.md)). No CI job publishes on every merge. **No live publish in this PR.**
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @inboxlink/sdk — host-app client for the InboxLink HTTP API.
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
* Copyright (c) 2026 Etienne Fokou
|
|
6
|
+
*/
|
|
7
|
+
import type { CreateLinkSessionInput, Grant, Message } from "@inboxlink/core";
|
|
8
|
+
export type { CreateLinkSessionInput, EmailAddress, Grant, GrantStatus, Message, MessageAttachment, Provider, } from "@inboxlink/core";
|
|
9
|
+
/** Documented Production origin. Used when `baseUrl` is omitted. */
|
|
10
|
+
export declare const INBOXLINK_PRODUCTION_URL = "https://inboxlink-two.vercel.app";
|
|
11
|
+
export type InboxLinkClientOptions = {
|
|
12
|
+
/**
|
|
13
|
+
* API origin. Defaults to {@link INBOXLINK_PRODUCTION_URL}.
|
|
14
|
+
* Override for local (`http://localhost:8787`) or self-hosted deployments.
|
|
15
|
+
*/
|
|
16
|
+
baseUrl?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Bearer secret (`INBOXLINK_API_SECRET`).
|
|
19
|
+
* Required only when the server runs `INBOXLINK_MODE=multi`.
|
|
20
|
+
* Omit for Production / `single` mode — the Authorization header is not sent.
|
|
21
|
+
*/
|
|
22
|
+
apiSecret?: string;
|
|
23
|
+
fetch?: typeof fetch;
|
|
24
|
+
};
|
|
25
|
+
export type ListMessagesOptions = {
|
|
26
|
+
/** Page size. Server currently accepts 1–25 (default 20). */
|
|
27
|
+
limit?: number;
|
|
28
|
+
/** Opaque pagination cursor from a previous `nextCursor`. */
|
|
29
|
+
cursor?: string;
|
|
30
|
+
};
|
|
31
|
+
export type IterateMessagesOptions = {
|
|
32
|
+
/** Skip messages with `receivedAt` earlier than this ISO timestamp. */
|
|
33
|
+
since?: string;
|
|
34
|
+
limit?: number;
|
|
35
|
+
};
|
|
36
|
+
export type LinkSessionResult = {
|
|
37
|
+
linkToken: string;
|
|
38
|
+
connectUrl: string;
|
|
39
|
+
sessionId: string;
|
|
40
|
+
expiresAt?: string;
|
|
41
|
+
};
|
|
42
|
+
export type ListMessagesResult = {
|
|
43
|
+
messages: Message[];
|
|
44
|
+
nextCursor?: string;
|
|
45
|
+
};
|
|
46
|
+
export type SyncResult = {
|
|
47
|
+
grantId: string;
|
|
48
|
+
status: string;
|
|
49
|
+
mode: string;
|
|
50
|
+
historyId?: string;
|
|
51
|
+
upserted?: number;
|
|
52
|
+
deleted?: number;
|
|
53
|
+
};
|
|
54
|
+
export type SyncOptions = {
|
|
55
|
+
mode?: "full" | "bootstrap" | "incremental";
|
|
56
|
+
};
|
|
57
|
+
export type ConnectRedirectParams = {
|
|
58
|
+
/** One-time token for `grants.exchange` / `completeConnect`. */
|
|
59
|
+
publicToken: string;
|
|
60
|
+
/** Original link token (optional correlation). */
|
|
61
|
+
linkToken?: string;
|
|
62
|
+
};
|
|
63
|
+
/** HTTP error from the InboxLink API (non-2xx). */
|
|
64
|
+
export declare class InboxLinkApiError extends Error {
|
|
65
|
+
readonly status: number;
|
|
66
|
+
readonly method: string;
|
|
67
|
+
readonly path: string;
|
|
68
|
+
readonly body: string;
|
|
69
|
+
/** Parsed `error` field when the body is JSON. */
|
|
70
|
+
readonly code?: string;
|
|
71
|
+
/** Parsed `detail` / guidance when the body is JSON. */
|
|
72
|
+
readonly detail?: string;
|
|
73
|
+
constructor(input: {
|
|
74
|
+
method: string;
|
|
75
|
+
path: string;
|
|
76
|
+
status: number;
|
|
77
|
+
body: string;
|
|
78
|
+
code?: string;
|
|
79
|
+
detail?: string;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Parse the host redirect URL (or query string) after Connect completes.
|
|
84
|
+
* Expects `public_token` (required) and optional `link_token`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function parseConnectRedirect(input: string | URL | {
|
|
87
|
+
searchParams: URLSearchParams;
|
|
88
|
+
}): ConnectRedirectParams;
|
|
89
|
+
/** Build the hosted Connect page URL for a link token (same shape as session.connectUrl). */
|
|
90
|
+
export declare function connectUrlForToken(linkToken: string, baseUrl?: string): string;
|
|
91
|
+
export declare class InboxLink {
|
|
92
|
+
readonly link: LinkApi;
|
|
93
|
+
readonly grants: GrantsApi;
|
|
94
|
+
readonly messages: MessagesApi;
|
|
95
|
+
readonly webhooks: WebhooksApi;
|
|
96
|
+
/** Resolved API origin (after defaults). */
|
|
97
|
+
readonly baseUrl: string;
|
|
98
|
+
constructor(options?: InboxLinkClientOptions);
|
|
99
|
+
/**
|
|
100
|
+
* High-level Connect entry: create a session and return `connectUrl` for the browser.
|
|
101
|
+
* Same as `link.createSession` — prefer this name in host apps.
|
|
102
|
+
*/
|
|
103
|
+
createConnectSession(input: CreateLinkSessionInput): Promise<LinkSessionResult>;
|
|
104
|
+
/**
|
|
105
|
+
* Finish Connect: exchange a one-time `public_token` (or a full redirect URL) for `grantId`.
|
|
106
|
+
* Call from your host redirect/BFF handler — never from a browser that holds an API secret.
|
|
107
|
+
*/
|
|
108
|
+
completeConnect(input: {
|
|
109
|
+
publicToken: string;
|
|
110
|
+
} | {
|
|
111
|
+
redirectUrl: string;
|
|
112
|
+
}): Promise<{
|
|
113
|
+
grantId: string;
|
|
114
|
+
}>;
|
|
115
|
+
}
|
|
116
|
+
declare class HttpClient {
|
|
117
|
+
private readonly fetchImpl;
|
|
118
|
+
private readonly baseUrl;
|
|
119
|
+
private readonly apiSecret?;
|
|
120
|
+
constructor(options: {
|
|
121
|
+
baseUrl: string;
|
|
122
|
+
apiSecret?: string;
|
|
123
|
+
fetch?: typeof fetch;
|
|
124
|
+
});
|
|
125
|
+
request<T>(method: string, path: string, body?: Record<string, unknown>): Promise<T>;
|
|
126
|
+
}
|
|
127
|
+
declare class LinkApi {
|
|
128
|
+
private readonly http;
|
|
129
|
+
constructor(http: HttpClient);
|
|
130
|
+
/** Create a Connect session for an end user. */
|
|
131
|
+
createSession(input: CreateLinkSessionInput): Promise<LinkSessionResult>;
|
|
132
|
+
}
|
|
133
|
+
declare class GrantsApi {
|
|
134
|
+
private readonly http;
|
|
135
|
+
constructor(http: HttpClient);
|
|
136
|
+
/** Exchange a one-time public token from Connect for a durable grant id. */
|
|
137
|
+
exchange(input: {
|
|
138
|
+
publicToken: string;
|
|
139
|
+
}): Promise<{
|
|
140
|
+
grantId: string;
|
|
141
|
+
}>;
|
|
142
|
+
list(externalUserId: string): Promise<{
|
|
143
|
+
grants: Grant[];
|
|
144
|
+
}>;
|
|
145
|
+
revoke(grantId: string): Promise<void>;
|
|
146
|
+
/** Run history sync (bootstrap / incremental / full). Maps to `POST /v1/grants/:grantId/sync`. */
|
|
147
|
+
sync(grantId: string, opts?: SyncOptions): Promise<SyncResult>;
|
|
148
|
+
}
|
|
149
|
+
declare class MessagesApi {
|
|
150
|
+
private readonly http;
|
|
151
|
+
constructor(http: HttpClient);
|
|
152
|
+
/**
|
|
153
|
+
* List normalized messages for a grant.
|
|
154
|
+
* Maps to `GET /v1/grants/:grantId/messages`.
|
|
155
|
+
*/
|
|
156
|
+
list(grantId: string, opts?: ListMessagesOptions): Promise<ListMessagesResult>;
|
|
157
|
+
/**
|
|
158
|
+
* Fetch a single message by id (InboxLink `msg_…` or provider Gmail id).
|
|
159
|
+
* Maps to `GET /v1/grants/:grantId/messages/:messageId`.
|
|
160
|
+
* Response includes optional attachment metadata (id, filename, mimeType, size) — not bytes.
|
|
161
|
+
*/
|
|
162
|
+
get(grantId: string, messageId: string): Promise<{
|
|
163
|
+
message: Message;
|
|
164
|
+
}>;
|
|
165
|
+
/** Walk list pages until exhausted (or filtered by `since`). */
|
|
166
|
+
iterate(grantId: string, opts?: IterateMessagesOptions): AsyncGenerator<Message>;
|
|
167
|
+
}
|
|
168
|
+
declare class WebhooksApi {
|
|
169
|
+
/** Verify `sha256=<hex>` HMAC signatures (constant-time). */
|
|
170
|
+
verify(input: {
|
|
171
|
+
payload: string;
|
|
172
|
+
signatureHeader: string;
|
|
173
|
+
secret: string;
|
|
174
|
+
}): boolean;
|
|
175
|
+
}
|
|
176
|
+
export { InboxLink as default };
|
|
177
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @inboxlink/sdk — host-app client for the InboxLink HTTP API.
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
* Copyright (c) 2026 Etienne Fokou
|
|
6
|
+
*/
|
|
7
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
8
|
+
/** Documented Production origin. Used when `baseUrl` is omitted. */
|
|
9
|
+
export const INBOXLINK_PRODUCTION_URL = "https://inboxlink-two.vercel.app";
|
|
10
|
+
/** HTTP error from the InboxLink API (non-2xx). */
|
|
11
|
+
export class InboxLinkApiError extends Error {
|
|
12
|
+
status;
|
|
13
|
+
method;
|
|
14
|
+
path;
|
|
15
|
+
body;
|
|
16
|
+
/** Parsed `error` field when the body is JSON. */
|
|
17
|
+
code;
|
|
18
|
+
/** Parsed `detail` / guidance when the body is JSON. */
|
|
19
|
+
detail;
|
|
20
|
+
constructor(input) {
|
|
21
|
+
const hint = input.detail ?? input.code;
|
|
22
|
+
const suffix = hint ? ` — ${hint}` : `: ${input.body.slice(0, 300)}`;
|
|
23
|
+
super(`InboxLink ${input.method} ${input.path} → ${input.status}${suffix}`);
|
|
24
|
+
this.name = "InboxLinkApiError";
|
|
25
|
+
this.method = input.method;
|
|
26
|
+
this.path = input.path;
|
|
27
|
+
this.status = input.status;
|
|
28
|
+
this.body = input.body;
|
|
29
|
+
this.code = input.code;
|
|
30
|
+
this.detail = input.detail;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parse the host redirect URL (or query string) after Connect completes.
|
|
35
|
+
* Expects `public_token` (required) and optional `link_token`.
|
|
36
|
+
*/
|
|
37
|
+
export function parseConnectRedirect(input) {
|
|
38
|
+
let params;
|
|
39
|
+
if (typeof input === "string") {
|
|
40
|
+
const trimmed = input.trim();
|
|
41
|
+
if (!trimmed) {
|
|
42
|
+
throw new Error("parseConnectRedirect: empty input. Pass the full redirect URL or a query string containing public_token.");
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
params = trimmed.includes("://")
|
|
46
|
+
? new URL(trimmed).searchParams
|
|
47
|
+
: new URLSearchParams(trimmed.startsWith("?") ? trimmed.slice(1) : trimmed);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
throw new Error("parseConnectRedirect: could not parse URL. Pass the full redirect URL your host received after Connect.");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if (input instanceof URL) {
|
|
54
|
+
params = input.searchParams;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
params = input.searchParams;
|
|
58
|
+
}
|
|
59
|
+
const publicToken = params.get("public_token")?.trim() || undefined;
|
|
60
|
+
if (!publicToken) {
|
|
61
|
+
throw new Error("parseConnectRedirect: missing public_token. Connect may have failed (InboxLink shows an error page instead of redirecting), or the user landed on the wrong route.");
|
|
62
|
+
}
|
|
63
|
+
const linkToken = params.get("link_token")?.trim() || undefined;
|
|
64
|
+
return { publicToken, linkToken };
|
|
65
|
+
}
|
|
66
|
+
/** Build the hosted Connect page URL for a link token (same shape as session.connectUrl). */
|
|
67
|
+
export function connectUrlForToken(linkToken, baseUrl = INBOXLINK_PRODUCTION_URL) {
|
|
68
|
+
const token = linkToken.trim();
|
|
69
|
+
if (!token) {
|
|
70
|
+
throw new Error("connectUrlForToken: linkToken is required");
|
|
71
|
+
}
|
|
72
|
+
const origin = ensureNoTrailingSlash(baseUrl || INBOXLINK_PRODUCTION_URL);
|
|
73
|
+
return `${origin}/v1/connect/${encodeURIComponent(token)}`;
|
|
74
|
+
}
|
|
75
|
+
export class InboxLink {
|
|
76
|
+
link;
|
|
77
|
+
grants;
|
|
78
|
+
messages;
|
|
79
|
+
webhooks;
|
|
80
|
+
/** Resolved API origin (after defaults). */
|
|
81
|
+
baseUrl;
|
|
82
|
+
constructor(options = {}) {
|
|
83
|
+
const baseUrl = ensureNoTrailingSlash(options.baseUrl?.trim() || INBOXLINK_PRODUCTION_URL);
|
|
84
|
+
if (!baseUrl) {
|
|
85
|
+
throw new Error("InboxLink: baseUrl is empty. Pass baseUrl or rely on the Production default.");
|
|
86
|
+
}
|
|
87
|
+
this.baseUrl = baseUrl;
|
|
88
|
+
const apiSecret = options.apiSecret?.trim() || undefined;
|
|
89
|
+
const http = new HttpClient({ baseUrl, apiSecret, fetch: options.fetch });
|
|
90
|
+
this.link = new LinkApi(http);
|
|
91
|
+
this.grants = new GrantsApi(http);
|
|
92
|
+
this.messages = new MessagesApi(http);
|
|
93
|
+
this.webhooks = new WebhooksApi();
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* High-level Connect entry: create a session and return `connectUrl` for the browser.
|
|
97
|
+
* Same as `link.createSession` — prefer this name in host apps.
|
|
98
|
+
*/
|
|
99
|
+
createConnectSession(input) {
|
|
100
|
+
return this.link.createSession(input);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Finish Connect: exchange a one-time `public_token` (or a full redirect URL) for `grantId`.
|
|
104
|
+
* Call from your host redirect/BFF handler — never from a browser that holds an API secret.
|
|
105
|
+
*/
|
|
106
|
+
completeConnect(input) {
|
|
107
|
+
const publicToken = "publicToken" in input && input.publicToken
|
|
108
|
+
? input.publicToken
|
|
109
|
+
: parseConnectRedirect(input.redirectUrl).publicToken;
|
|
110
|
+
return this.grants.exchange({ publicToken });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
class HttpClient {
|
|
114
|
+
fetchImpl;
|
|
115
|
+
baseUrl;
|
|
116
|
+
apiSecret;
|
|
117
|
+
constructor(options) {
|
|
118
|
+
this.baseUrl = options.baseUrl;
|
|
119
|
+
this.apiSecret = options.apiSecret;
|
|
120
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
121
|
+
}
|
|
122
|
+
async request(method, path, body) {
|
|
123
|
+
const url = new URL(path, ensureTrailingSlash(this.baseUrl));
|
|
124
|
+
const headers = {
|
|
125
|
+
"content-type": "application/json",
|
|
126
|
+
accept: "application/json",
|
|
127
|
+
};
|
|
128
|
+
if (this.apiSecret) {
|
|
129
|
+
headers.authorization = `Bearer ${this.apiSecret}`;
|
|
130
|
+
}
|
|
131
|
+
const res = await this.fetchImpl(url, {
|
|
132
|
+
method,
|
|
133
|
+
headers,
|
|
134
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
135
|
+
});
|
|
136
|
+
if (!res.ok) {
|
|
137
|
+
const text = await res.text();
|
|
138
|
+
const parsed = tryParseErrorBody(text);
|
|
139
|
+
throw new InboxLinkApiError({
|
|
140
|
+
method,
|
|
141
|
+
path,
|
|
142
|
+
status: res.status,
|
|
143
|
+
body: text,
|
|
144
|
+
code: parsed?.code,
|
|
145
|
+
detail: parsed?.detail,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (res.status === 204) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
return (await res.json());
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
class LinkApi {
|
|
155
|
+
http;
|
|
156
|
+
constructor(http) {
|
|
157
|
+
this.http = http;
|
|
158
|
+
}
|
|
159
|
+
/** Create a Connect session for an end user. */
|
|
160
|
+
createSession(input) {
|
|
161
|
+
if (!input.externalUserId?.trim()) {
|
|
162
|
+
throw new Error("link.createSession: externalUserId is required");
|
|
163
|
+
}
|
|
164
|
+
if (!input.redirectUri?.trim()) {
|
|
165
|
+
throw new Error("link.createSession: redirectUri is required (your host callback URL that receives public_token — not the Google OAuth redirect).");
|
|
166
|
+
}
|
|
167
|
+
return this.http.request("POST", "v1/link/sessions", {
|
|
168
|
+
externalUserId: input.externalUserId,
|
|
169
|
+
redirectUri: input.redirectUri,
|
|
170
|
+
products: input.products ?? ["messages"],
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
class GrantsApi {
|
|
175
|
+
http;
|
|
176
|
+
constructor(http) {
|
|
177
|
+
this.http = http;
|
|
178
|
+
}
|
|
179
|
+
/** Exchange a one-time public token from Connect for a durable grant id. */
|
|
180
|
+
exchange(input) {
|
|
181
|
+
if (!input.publicToken?.trim()) {
|
|
182
|
+
throw new Error("grants.exchange: publicToken is required. Read it from the Connect redirect query (?public_token=…) via parseConnectRedirect or completeConnect.");
|
|
183
|
+
}
|
|
184
|
+
return this.http.request("POST", "v1/grants/exchange", input);
|
|
185
|
+
}
|
|
186
|
+
list(externalUserId) {
|
|
187
|
+
return this.http.request("GET", `v1/grants?externalUserId=${encodeURIComponent(externalUserId)}`);
|
|
188
|
+
}
|
|
189
|
+
revoke(grantId) {
|
|
190
|
+
return this.http.request("DELETE", `v1/grants/${encodeURIComponent(grantId)}`);
|
|
191
|
+
}
|
|
192
|
+
/** Run history sync (bootstrap / incremental / full). Maps to `POST /v1/grants/:grantId/sync`. */
|
|
193
|
+
sync(grantId, opts) {
|
|
194
|
+
const body = opts?.mode && opts.mode !== "incremental" ? { mode: opts.mode } : undefined;
|
|
195
|
+
return this.http.request("POST", `v1/grants/${encodeURIComponent(grantId)}/sync`, body);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
class MessagesApi {
|
|
199
|
+
http;
|
|
200
|
+
constructor(http) {
|
|
201
|
+
this.http = http;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* List normalized messages for a grant.
|
|
205
|
+
* Maps to `GET /v1/grants/:grantId/messages`.
|
|
206
|
+
*/
|
|
207
|
+
list(grantId, opts) {
|
|
208
|
+
const q = new URLSearchParams();
|
|
209
|
+
if (opts?.limit !== undefined)
|
|
210
|
+
q.set("limit", String(opts.limit));
|
|
211
|
+
if (opts?.cursor)
|
|
212
|
+
q.set("cursor", opts.cursor);
|
|
213
|
+
const qs = q.toString();
|
|
214
|
+
return this.http.request("GET", `v1/grants/${encodeURIComponent(grantId)}/messages${qs ? `?${qs}` : ""}`);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Fetch a single message by id (InboxLink `msg_…` or provider Gmail id).
|
|
218
|
+
* Maps to `GET /v1/grants/:grantId/messages/:messageId`.
|
|
219
|
+
* Response includes optional attachment metadata (id, filename, mimeType, size) — not bytes.
|
|
220
|
+
*/
|
|
221
|
+
get(grantId, messageId) {
|
|
222
|
+
return this.http.request("GET", `v1/grants/${encodeURIComponent(grantId)}/messages/${encodeURIComponent(messageId)}`);
|
|
223
|
+
}
|
|
224
|
+
/** Walk list pages until exhausted (or filtered by `since`). */
|
|
225
|
+
async *iterate(grantId, opts) {
|
|
226
|
+
let cursor;
|
|
227
|
+
for (;;) {
|
|
228
|
+
const page = await this.list(grantId, { limit: opts?.limit ?? 20, cursor });
|
|
229
|
+
for (const msg of page.messages) {
|
|
230
|
+
if (opts?.since && msg.receivedAt < opts.since)
|
|
231
|
+
continue;
|
|
232
|
+
yield msg;
|
|
233
|
+
}
|
|
234
|
+
if (!page.nextCursor)
|
|
235
|
+
break;
|
|
236
|
+
cursor = page.nextCursor;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
class WebhooksApi {
|
|
241
|
+
/** Verify `sha256=<hex>` HMAC signatures (constant-time). */
|
|
242
|
+
verify(input) {
|
|
243
|
+
const expected = createHmac("sha256", input.secret).update(input.payload).digest("hex");
|
|
244
|
+
const provided = input.signatureHeader.replace(/^sha256=/i, "").trim();
|
|
245
|
+
try {
|
|
246
|
+
const a = Buffer.from(expected, "hex");
|
|
247
|
+
const b = Buffer.from(provided, "hex");
|
|
248
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function ensureTrailingSlash(base) {
|
|
256
|
+
return base.endsWith("/") ? base : `${base}/`;
|
|
257
|
+
}
|
|
258
|
+
function ensureNoTrailingSlash(base) {
|
|
259
|
+
return base.replace(/\/+$/, "");
|
|
260
|
+
}
|
|
261
|
+
function tryParseErrorBody(text) {
|
|
262
|
+
try {
|
|
263
|
+
const json = JSON.parse(text);
|
|
264
|
+
const code = typeof json.error === "string" ? json.error : undefined;
|
|
265
|
+
const detail = typeof json.detail === "string"
|
|
266
|
+
? json.detail
|
|
267
|
+
: typeof json.message === "string"
|
|
268
|
+
? json.message
|
|
269
|
+
: undefined;
|
|
270
|
+
if (code || detail)
|
|
271
|
+
return { code, detail };
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
// non-JSON body
|
|
275
|
+
}
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
export { InboxLink as default };
|
|
279
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@inboxlink/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Host-app client for InboxLink HTTP API",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@inboxlink/core": "0.1.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"tsx": "^4.19.3"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/EtienneFokou-E18560/inboxlink.git",
|
|
33
|
+
"directory": "packages/sdk"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/EtienneFokou-E18560/inboxlink/issues"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/EtienneFokou-E18560/inboxlink/tree/main/packages/sdk#readme",
|
|
39
|
+
"keywords": [
|
|
40
|
+
"inboxlink",
|
|
41
|
+
"email",
|
|
42
|
+
"oauth",
|
|
43
|
+
"sdk",
|
|
44
|
+
"client"
|
|
45
|
+
],
|
|
46
|
+
"sideEffects": false,
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=22"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc -b tsconfig.json",
|
|
52
|
+
"typecheck": "tsc -b tsconfig.json",
|
|
53
|
+
"lint": "tsc -b tsconfig.json",
|
|
54
|
+
"test": "node --import tsx --test src/client.test.ts"
|
|
55
|
+
}
|
|
56
|
+
}
|