Skip to content

Commit 30a2afd

Browse files
committed
Rewrite README around usage
State that Gmail is the only supported API, install the package and its peers from npm, and add a quickstart, a tool reference with approval gates, the sidecar-bundle and interchange manifest entries, and an authenticated fetchImpl for createGmailClient. Development and live Gmail checks move to CONTRIBUTING.md.
1 parent 4391adb commit 30a2afd

2 files changed

Lines changed: 127 additions & 41 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Contributing
2+
3+
## Development
4+
5+
```bash
6+
bun install
7+
bun run typecheck
8+
bun run test
9+
bun run build
10+
```
11+
12+
The tests inject `fetch` implementations and do not call Gmail.
13+
14+
## Live Gmail checks
15+
16+
Use a dedicated Gmail fixture account and a Desktop OAuth client granted only
17+
`gmail.modify`. The read smoke requires a query that matches exactly one
18+
one-message thread:
19+
20+
```bash
21+
GMAIL_LIVE_TEST=1 \
22+
GMAIL_LIVE_CLIENT_ID='...' \
23+
GMAIL_LIVE_CLIENT_SECRET='...' \
24+
GMAIL_LIVE_FIXTURE_QUERY='subject:(interchange-gmail-e2e-fixture)' \
25+
bun run test:live
26+
```
27+
28+
The full live suite has been verified against a dedicated Gmail fixture account.
29+
It exercises every Gmail tool:
30+
31+
- `gmail_search_threads` finds the one-message fixture thread.
32+
- `gmail_get_thread` and `gmail_get_message` retrieve its metadata.
33+
- `gmail_list_labels` lists the account labels.
34+
- `gmail_create_draft` and `gmail_list_drafts` create and find a disposable
35+
draft, which the suite then deletes.
36+
- `gmail_label_message` and `gmail_unlabel_message` add and remove `STARRED`
37+
on the fixture message.
38+
- `gmail_label_thread` and `gmail_unlabel_thread` add and remove `STARRED`
39+
on every message in the fixture thread.
40+
41+
Add `GMAIL_LIVE_MUTATION_TEST=1` to run the draft and label checks. The suite
42+
deletes its draft, restores the fixture labels, and never sends email.
43+
44+
The first run opens Google OAuth and stores the refresh token in the ignored
45+
`.local/gmail-live-token.json` file. Set `GMAIL_LIVE_TOKEN_FILE` when using a
46+
different token file. Credentials and message contents are not logged.

‎README.md‎

Lines changed: 81 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,103 @@
11
# @corbits/google-tools
22

3-
Google API clients and Interchange tools, starting with Gmail. Authentication
4-
is supplied through the Interchange `gmail-api` mediated credential; the
5-
package never accepts or returns raw tokens.
3+
Gmail is the only Google API supported today. The package provides a Gmail
4+
API client and Interchange tools. Authentication is supplied through the
5+
Interchange `gmail-api` mediated credential; the package never accepts or
6+
returns raw tokens.
67

78
## Requirements
89

9-
Node.js 24 or newer (`engines.node >=24`).
10+
Node.js 24 or newer (`engines.node >=24`). `@intx/agent` and `@intx/types`
11+
are required peer dependencies.
1012

1113
## Install
1214

1315
```bash
14-
bun add github:corbitsdev/google-tools
16+
npm add @corbits/google-tools
1517
```
1618

17-
## Working on it
19+
## Quickstart
20+
21+
`createGmailTools` resolves the `gmail-api` credential from the
22+
`RuntimeCapabilities` it is given. An Interchange host supplies those
23+
capabilities; outside a host, build them with `createRuntimeCapabilities` from
24+
`@intx/types` and an http credential that adds a Gmail OAuth access token
25+
granted `https://www.googleapis.com/auth/gmail.modify`:
26+
27+
```ts
28+
import { createGmailTools } from "@corbits/google-tools";
29+
import { createRuntimeCapabilities } from "@intx/types/runtime-capabilities";
30+
31+
function gmailFetch(input: string | URL | Request, init?: RequestInit) {
32+
const request = new Request(input, init);
33+
request.headers.set("Authorization", `Bearer ${process.env.GMAIL_ACCESS_TOKEN}`);
34+
return fetch(request);
35+
}
36+
37+
const capabilities = createRuntimeCapabilities({
38+
credentials: { resolve: async () => ({ kind: "http", fetch: gmailFetch, dispose() {} }) },
39+
});
40+
const tools = createGmailTools({ capabilities });
41+
const result = await tools.run({ id: "1", name: "gmail_list_labels", arguments: {} }, AbortSignal.timeout(10_000));
42+
console.log(result.content); // { data: { labels: [{ id: "INBOX", name: "INBOX", ... }] } }
43+
await tools.dispose();
44+
```
1845

19-
```bash
20-
bun install
21-
bun run typecheck
22-
bun test
23-
bun run build
46+
## Tools
47+
48+
| Tool | Purpose | Approval |
49+
| --- | --- | --- |
50+
| `gmail_search_threads` | Search the mailbox and return thread summaries. | No |
51+
| `gmail_get_thread` | Fetch one thread with selected message detail. | No |
52+
| `gmail_get_message` | Fetch one message with selected detail. | No |
53+
| `gmail_list_labels` | List the mailbox labels. | No |
54+
| `gmail_create_draft` | Create a draft, optionally as a reply. Never sends. | Yes |
55+
| `gmail_list_drafts` | List drafts with Gmail-query filtering. | No |
56+
| `gmail_label_message` | Add labels to a message. | Yes |
57+
| `gmail_unlabel_message` | Remove labels from a message. | Yes |
58+
| `gmail_label_thread` | Add labels to every message in a thread. | Yes |
59+
| `gmail_unlabel_thread` | Remove labels from every message in a thread. | Yes |
60+
61+
Tools marked Yes are declared with `approval: "ask"` in the sidecar bundle, so
62+
Interchange gates each invocation behind approval.
63+
64+
## Using with Interchange
65+
66+
The `./sidecar-bundle` export is the tool bundle Interchange loads. It exports
67+
`gmail`, a `defineTool` factory that requires `capabilities` on the agent env
68+
and builds the tools with `createGmailTools`:
69+
70+
```ts
71+
import { gmail } from "@corbits/google-tools/sidecar-bundle";
2472
```
2573

26-
The tests inject `fetch` implementations and do not call Gmail.
74+
`package.json` declares the bundle for Interchange's tool-package loader:
2775

28-
## Live Gmail checks
76+
- `interchange.tools` points at `./dist/sidecar-bundle.js`.
77+
- `interchange.credentials` requests the `gmail-api` handle with the
78+
`https://www.googleapis.com/auth/gmail.modify` scope. The host binds that
79+
handle to a Google OAuth credential and hands it to the bundle through
80+
`env.capabilities`.
2981

30-
Use a dedicated Gmail fixture account and a Desktop OAuth client granted only
31-
`gmail.modify`. The read smoke requires a query that matches exactly one
32-
one-message thread:
82+
## Gmail client
3383

34-
```bash
35-
GMAIL_LIVE_TEST=1 \
36-
GMAIL_LIVE_CLIENT_ID='...' \
37-
GMAIL_LIVE_CLIENT_SECRET='...' \
38-
GMAIL_LIVE_FIXTURE_QUERY='subject:(interchange-gmail-e2e-fixture)' \
39-
bun run test:live
84+
`createGmailClient` calls the Gmail REST API directly. It takes a `fetchImpl`
85+
that authenticates each request; the `gmailFetch` wrapper from the quickstart
86+
works as-is:
87+
88+
```ts
89+
import { createGmailClient } from "@corbits/google-tools";
90+
91+
const client = createGmailClient({ fetchImpl: gmailFetch });
92+
const { labels } = await client.listLabels();
4093
```
4194

42-
The full live suite has been verified against a dedicated Gmail fixture account.
43-
It exercises every Gmail tool:
44-
45-
- `gmail_search_threads` finds the one-message fixture thread.
46-
- `gmail_get_thread` and `gmail_get_message` retrieve its metadata.
47-
- `gmail_list_labels` lists the account labels.
48-
- `gmail_create_draft` and `gmail_list_drafts` create and find a disposable
49-
draft, which the suite then deletes.
50-
- `gmail_label_message` and `gmail_unlabel_message` add and remove `STARRED`
51-
on the fixture message.
52-
- `gmail_label_thread` and `gmail_unlabel_thread` add and remove `STARRED`
53-
on every message in the fixture thread.
54-
55-
Add `GMAIL_LIVE_MUTATION_TEST=1` to run the draft and label checks. The suite
56-
deletes its draft, restores the fixture labels, and never sends email.
57-
58-
The first run opens Google OAuth and stores the refresh token in the ignored
59-
`.local/gmail-live-token.json` file. Set `GMAIL_LIVE_TOKEN_FILE` when using a
60-
different token file. Credentials and message contents are not logged.
95+
Inside Interchange, resolve the `gmail-api` handle from `capabilities` and pass
96+
the credential's `fetch` instead.
97+
98+
## Contributing
99+
100+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for development and live Gmail checks.
61101

62102
## License
63103

0 commit comments

Comments
 (0)