@aaronsb/google-workspace-mcp 4.2.0 → 4.3.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 +6 -5
- package/build/accounts/auth.d.ts +18 -2
- package/build/accounts/auth.js +31 -7
- package/build/accounts/auth.js.map +1 -1
- package/build/accounts/credentials.d.ts +20 -0
- package/build/accounts/credentials.js.map +1 -1
- package/build/accounts/oauth.d.ts +51 -1
- package/build/accounts/oauth.js +69 -5
- package/build/accounts/oauth.js.map +1 -1
- package/build/accounts/registry.d.ts +2 -1
- package/build/accounts/registry.js +2 -2
- package/build/accounts/registry.js.map +1 -1
- package/build/factory/manifest/calendar.yaml +22 -22
- package/build/factory/manifest/contacts.yaml +247 -0
- package/build/factory/manifest/drive.yaml +16 -16
- package/build/factory/manifest/gmail.yaml +18 -18
- package/build/factory/manifest/meet.yaml +91 -13
- package/build/factory/manifest/sheets.yaml +29 -29
- package/build/factory/manifest/tasks.yaml +14 -14
- package/build/factory/patches.js +2 -0
- package/build/factory/patches.js.map +1 -1
- package/build/factory/safety.js +4 -0
- package/build/factory/safety.js.map +1 -1
- package/build/google/descriptor.d.ts +8 -0
- package/build/google/descriptor.js +9 -2
- package/build/google/descriptor.js.map +1 -1
- package/build/google/descriptor.json +1883 -0
- package/build/google/methods.d.ts +4 -1
- package/build/server/handler.js +16 -1
- package/build/server/handler.js.map +1 -1
- package/build/server/handlers/accounts.js +100 -6
- package/build/server/handlers/accounts.js.map +1 -1
- package/build/server/queue.d.ts +1 -1
- package/build/server/queue.js +16 -1
- package/build/server/queue.js.map +1 -1
- package/build/server/tools.js +31 -1
- package/build/server/tools.js.map +1 -1
- package/build/services/calendar/patch.js +62 -8
- package/build/services/calendar/patch.js.map +1 -1
- package/build/services/contacts/patch.d.ts +31 -0
- package/build/services/contacts/patch.js +496 -0
- package/build/services/contacts/patch.js.map +1 -0
- package/build/services/meet/patch.js +202 -0
- package/build/services/meet/patch.js.map +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://nodejs.org)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
**Give your AI agent real access to Google Workspace** — Gmail, Calendar, Drive, Docs, Sheets, Tasks and
|
|
8
|
+
**Give your AI agent real access to Google Workspace** — Gmail, Calendar, Drive, Docs, Sheets, Tasks, Meet and Contacts — from one MCP server, across as many accounts as you have.
|
|
9
9
|
|
|
10
10
|
Search your mail, check your calendar, write a doc, file a task — in conversation, as yourself.
|
|
11
11
|
|
|
@@ -15,7 +15,7 @@ First, you need **Google OAuth credentials** — the one prerequisite common to
|
|
|
15
15
|
|
|
16
16
|
1. Go to [console.cloud.google.com/apis/credentials](https://console.cloud.google.com/apis/credentials)
|
|
17
17
|
2. Create an **OAuth 2.0 Client ID**, application type **Desktop app**
|
|
18
|
-
3. Enable the APIs you want (Gmail, Calendar, Drive, Sheets, Docs, Tasks, Meet)
|
|
18
|
+
3. Enable the APIs you want (Gmail, Calendar, Drive, Sheets, Docs, Tasks, Meet — and **People API** for contacts, which is what Google calls it in the console)
|
|
19
19
|
4. Keep the **Client ID** and **Client Secret** handy — you'll paste them in below
|
|
20
20
|
|
|
21
21
|
Then pick the path that matches how you work. All three run the same server.
|
|
@@ -90,7 +90,7 @@ flowchart LR
|
|
|
90
90
|
agent["🤖 Your AI agent<br>Claude Desktop, Claude Code…"]
|
|
91
91
|
server["⚙️ This MCP server<br>picks the right account,<br>builds the real request"]
|
|
92
92
|
keys[("🔑 Your accounts<br>OAuth tokens, kept<br>on your own machine")]
|
|
93
|
-
google["☁️ Google<br>Gmail · Calendar · Drive<br>
|
|
93
|
+
google["☁️ Google<br>Gmail · Calendar · Drive · Docs<br>Sheets · Tasks · Meet · Contacts"]
|
|
94
94
|
|
|
95
95
|
human -->|"“what's on my calendar?”"| agent
|
|
96
96
|
agent -->|"tool call"| server
|
|
@@ -117,7 +117,7 @@ flowchart LR
|
|
|
117
117
|
|
|
118
118
|
## What it can do
|
|
119
119
|
|
|
120
|
-
**
|
|
120
|
+
**12 tools across 8 Google services**, plus multi-account handling, batching, content authoring, and a file sandbox.
|
|
121
121
|
|
|
122
122
|
| Tool | What It Does |
|
|
123
123
|
|------|--------------|
|
|
@@ -127,7 +127,8 @@ flowchart LR
|
|
|
127
127
|
| `manage_sheets` | Sheets — read / write ranges (row-numbered output), append, clear, manage tabs, copy / duplicate / rename |
|
|
128
128
|
| `manage_docs` | Docs — get, create, append, insert text, find-and-replace |
|
|
129
129
|
| `manage_tasks` | Tasks — list / create / update / complete tasks and task lists |
|
|
130
|
-
| `manage_meet` | Meet — browse past conferences, participants, transcripts, recordings, smart notes |
|
|
130
|
+
| `manage_meet` | Meet — create and configure meeting spaces, see who is in a call now, browse past conferences, participants, transcripts, recordings, smart notes |
|
|
131
|
+
| `manage_contacts` | Contacts — look people up in your saved contacts, the addresses you have only corresponded with, and your organization's directory; create, update and delete contacts |
|
|
131
132
|
| `manage_accounts` | Multi-account lifecycle — add accounts, manage credentials and scopes |
|
|
132
133
|
| `manage_scratchpad` | Compose / edit multi-line content (line- or JSON-path-addressed), attach files, send to any target; JSON mode live-syncs to Docs / Sheets |
|
|
133
134
|
| `manage_workspace` | File operations in the workspace sandbox (exchange point for attachments, downloads, exports) |
|
package/build/accounts/auth.d.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import type { AccessLevel } from './oauth.js';
|
|
1
2
|
export interface AuthResult {
|
|
2
3
|
status: 'success' | 'error';
|
|
3
4
|
account?: string;
|
|
4
5
|
credentialPath?: string;
|
|
5
6
|
error?: string;
|
|
6
7
|
errorType?: string;
|
|
8
|
+
/** What the account was authorized for. */
|
|
9
|
+
access?: AccessLevel;
|
|
10
|
+
/**
|
|
11
|
+
* Services asked for as read-only that can still write, because Google offers no
|
|
12
|
+
* read-only scope for them. Non-empty means this account got more access than was
|
|
13
|
+
* asked for, and the response has to say so (ADR-202).
|
|
14
|
+
*/
|
|
15
|
+
stillAllowWrites?: string[];
|
|
7
16
|
}
|
|
8
17
|
export interface AccountStatus {
|
|
9
18
|
email: string;
|
|
@@ -11,17 +20,24 @@ export interface AccountStatus {
|
|
|
11
20
|
scopes: string[];
|
|
12
21
|
scopeCount: number;
|
|
13
22
|
hasRefreshToken: boolean;
|
|
23
|
+
/** Absent on credentials written before ADR-202, which are all read/write. */
|
|
24
|
+
access: AccessLevel;
|
|
25
|
+
/** Services that can still write despite `access: 'read'`. Empty for full access. */
|
|
26
|
+
stillAllowWrites: string[];
|
|
14
27
|
}
|
|
15
28
|
/**
|
|
16
29
|
* Authenticate a new account via our own OAuth2 flow.
|
|
17
30
|
* Requests all service scopes by default.
|
|
31
|
+
*
|
|
32
|
+
* `access` defaults to 'readwrite', so an account authorized without naming it is
|
|
33
|
+
* granted exactly what it would have been before ADR-202.
|
|
18
34
|
*/
|
|
19
|
-
export declare function authenticateAccount(clientId: string, clientSecret: string): Promise<AuthResult>;
|
|
35
|
+
export declare function authenticateAccount(clientId: string, clientSecret: string, access?: AccessLevel): Promise<AuthResult>;
|
|
20
36
|
/**
|
|
21
37
|
* Re-authenticate with a specific set of services.
|
|
22
38
|
* Used by the `scopes` operation as an escape hatch.
|
|
23
39
|
*/
|
|
24
|
-
export declare function reauthWithServices(clientId: string, clientSecret: string, services: string): Promise<AuthResult>;
|
|
40
|
+
export declare function reauthWithServices(clientId: string, clientSecret: string, services: string, access?: AccessLevel): Promise<AuthResult>;
|
|
25
41
|
/**
|
|
26
42
|
* Check account status: token validity and granted scopes.
|
|
27
43
|
* Reads scopes from the per-account credential file.
|
package/build/accounts/auth.js
CHANGED
|
@@ -5,18 +5,23 @@ import { getAccessToken, invalidateToken } from './token-service.js';
|
|
|
5
5
|
/**
|
|
6
6
|
* Authenticate a new account via our own OAuth2 flow.
|
|
7
7
|
* Requests all service scopes by default.
|
|
8
|
+
*
|
|
9
|
+
* `access` defaults to 'readwrite', so an account authorized without naming it is
|
|
10
|
+
* granted exactly what it would have been before ADR-202.
|
|
8
11
|
*/
|
|
9
|
-
export async function authenticateAccount(clientId, clientSecret) {
|
|
10
|
-
const scopes = scopesForServices(ALL_SERVICES);
|
|
11
|
-
|
|
12
|
+
export async function authenticateAccount(clientId, clientSecret, access = 'readwrite') {
|
|
13
|
+
const { scopes, stillAllowWrites } = scopesForServices(ALL_SERVICES, access);
|
|
14
|
+
const result = await runOAuth(clientId, clientSecret, scopes, access, stillAllowWrites);
|
|
15
|
+
return { ...result, access, stillAllowWrites };
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
18
|
* Re-authenticate with a specific set of services.
|
|
15
19
|
* Used by the `scopes` operation as an escape hatch.
|
|
16
20
|
*/
|
|
17
|
-
export async function reauthWithServices(clientId, clientSecret, services) {
|
|
18
|
-
const scopes = scopesForServices(services);
|
|
19
|
-
|
|
21
|
+
export async function reauthWithServices(clientId, clientSecret, services, access = 'readwrite') {
|
|
22
|
+
const { scopes, stillAllowWrites } = scopesForServices(services, access);
|
|
23
|
+
const result = await runOAuth(clientId, clientSecret, scopes, access, stillAllowWrites);
|
|
24
|
+
return { ...result, access, stillAllowWrites };
|
|
20
25
|
}
|
|
21
26
|
/**
|
|
22
27
|
* Check account status: token validity and granted scopes.
|
|
@@ -32,6 +37,8 @@ export async function checkAccountStatus(email) {
|
|
|
32
37
|
scopes: [],
|
|
33
38
|
scopeCount: 0,
|
|
34
39
|
hasRefreshToken: false,
|
|
40
|
+
access: 'readwrite',
|
|
41
|
+
stillAllowWrites: [],
|
|
35
42
|
};
|
|
36
43
|
}
|
|
37
44
|
const cred = await readCredential(email);
|
|
@@ -51,18 +58,35 @@ export async function checkAccountStatus(email) {
|
|
|
51
58
|
scopes,
|
|
52
59
|
scopeCount: scopes.length,
|
|
53
60
|
hasRefreshToken,
|
|
61
|
+
// Absent means read/write — see AuthorizedUserCredential.access.
|
|
62
|
+
access: cred.access ?? 'readwrite',
|
|
63
|
+
stillAllowWrites: cred.stillAllowWrites ?? [],
|
|
54
64
|
};
|
|
55
65
|
}
|
|
56
66
|
// --- Internal ---
|
|
57
|
-
async function runOAuth(clientId, clientSecret, scopes) {
|
|
67
|
+
async function runOAuth(clientId, clientSecret, scopes, access = 'readwrite', stillAllowWrites = []) {
|
|
58
68
|
try {
|
|
59
69
|
const result = await runOAuthFlow(clientId, clientSecret, scopes);
|
|
70
|
+
// `result.scopes` is what Google GRANTED, which is not always what was asked for:
|
|
71
|
+
// the consent screen lets the user untick individual permissions before approving.
|
|
72
|
+
// Storing what was granted rather than what was requested means the call-time check
|
|
73
|
+
// in factory/safety.ts tests what the token can actually do (ADR-202).
|
|
74
|
+
//
|
|
75
|
+
// `access` is stored because nothing else records what this account was authorized
|
|
76
|
+
// FOR. The granted scopes say what the token can do; they do not say whether a human
|
|
77
|
+
// chose to hold it back. `status` reads it, and the call-time policy in ADR-202 will.
|
|
78
|
+
//
|
|
79
|
+
// It is NOT needed to protect `refresh`: refreshAccessToken posts grant_type=
|
|
80
|
+
// refresh_token with no scope parameter and never writes a credential, so a refresh
|
|
81
|
+
// cannot widen anything. An earlier version of this comment claimed otherwise.
|
|
60
82
|
await saveCredential(result.email, {
|
|
61
83
|
type: 'authorized_user',
|
|
62
84
|
client_id: clientId,
|
|
63
85
|
client_secret: clientSecret,
|
|
64
86
|
refresh_token: result.refreshToken,
|
|
65
87
|
scopes: result.scopes,
|
|
88
|
+
access,
|
|
89
|
+
...(stillAllowWrites.length ? { stillAllowWrites } : {}),
|
|
66
90
|
});
|
|
67
91
|
invalidateToken(result.email);
|
|
68
92
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/accounts/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/accounts/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,27 @@ export interface AuthorizedUserCredential {
|
|
|
3
3
|
client_id: string;
|
|
4
4
|
client_secret: string;
|
|
5
5
|
refresh_token: string;
|
|
6
|
+
/**
|
|
7
|
+
* The scopes Google actually GRANTED. Can be fewer than were requested: the consent
|
|
8
|
+
* screen lets the user untick individual permissions before approving.
|
|
9
|
+
*/
|
|
6
10
|
scopes?: string[];
|
|
11
|
+
/**
|
|
12
|
+
* What this account was authorized for (ADR-202).
|
|
13
|
+
*
|
|
14
|
+
* ABSENT means read/write. Every credential written before ADR-202 lacks the field and
|
|
15
|
+
* carries read/write scopes, so absence and 'readwrite' are the same claim — reading it
|
|
16
|
+
* as 'read' would lock existing accounts out of operations their tokens permit.
|
|
17
|
+
*/
|
|
18
|
+
access?: 'read' | 'readwrite';
|
|
19
|
+
/**
|
|
20
|
+
* Services that were asked for as read-only and can still write, because Google offers
|
|
21
|
+
* no read-only scope for them and the caller confirmed anyway.
|
|
22
|
+
*
|
|
23
|
+
* Stored because `access` alone would misdescribe such an account: it says 'read' while
|
|
24
|
+
* the token can change these services.
|
|
25
|
+
*/
|
|
26
|
+
stillAllowWrites?: string[];
|
|
7
27
|
}
|
|
8
28
|
export declare function hasCredential(email: string): Promise<boolean>;
|
|
9
29
|
export declare function saveCredential(email: string, credential: AuthorizedUserCredential): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/accounts/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/accounts/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
/** Service name → OAuth scope URL(s). */
|
|
2
2
|
export declare const SERVICE_SCOPE_MAP: Record<string, string[]>;
|
|
3
|
+
/**
|
|
4
|
+
* Service name → READ-ONLY scope URL(s), for accounts authorized with `access: 'read'`.
|
|
5
|
+
*
|
|
6
|
+
* A service is missing from this map when Google offers no read-only scope for it. That
|
|
7
|
+
* is NOT treated as "use the read/write scope and say nothing": someone who asked for
|
|
8
|
+
* read access would get write access without being told. `scopesForServices` reports
|
|
9
|
+
* those services instead, so the person consenting can be told before the browser opens
|
|
10
|
+
* (ADR-202).
|
|
11
|
+
*
|
|
12
|
+
* Every service currently has an entry, so nothing is granted more than was asked for
|
|
13
|
+
* today. The reporting path still exists because the next service added may not have
|
|
14
|
+
* one, and finding that out from a silently broad token is the wrong way to find out.
|
|
15
|
+
*
|
|
16
|
+
* Measured against descriptor.json rather than assumed:
|
|
17
|
+
*
|
|
18
|
+
* - calendar, docs, gmail, tasks — the scope below covers every GET method exposed.
|
|
19
|
+
* - meet — `meetings.space.readonly` authorizes every READ manage_meet exposes: all the
|
|
20
|
+
* conference-record operations, plus getSpace. The tool also creates, updates and ends
|
|
21
|
+
* meeting spaces, and those three need `meetings.space.created` or `.settings`, so a
|
|
22
|
+
* read-only meet account holds the readonly scope alone and Google refuses the writes.
|
|
23
|
+
* That is the mapping working, not a gap in it. Meet was very nearly left out of this
|
|
24
|
+
* map entirely by reading "has no read-only variant" off the scope list instead of off
|
|
25
|
+
* what each operation needs.
|
|
26
|
+
* - drive, sheets — two GET methods and one respectively that no read-only scope covers,
|
|
27
|
+
* so read access there allows less than full access but slightly more than reading.
|
|
28
|
+
* - contacts — only the first of its three scopes has a write form. `contacts.readonly`
|
|
29
|
+
* replaces `contacts`; `contacts.other.readonly` and `directory.readonly` are already
|
|
30
|
+
* read-only and so are identical in both maps. A read-only contacts account reaches
|
|
31
|
+
* every read manage_contacts has and is refused `create` by Google, which is the
|
|
32
|
+
* mapping working.
|
|
33
|
+
*/
|
|
34
|
+
export declare const SERVICE_SCOPE_MAP_READONLY: Record<string, string[]>;
|
|
35
|
+
/** How much authority an account's token carries. */
|
|
36
|
+
export type AccessLevel = 'read' | 'readwrite';
|
|
3
37
|
/** All service names that have scope mappings. */
|
|
4
38
|
export declare const ALL_SERVICES: string;
|
|
5
39
|
export interface OAuthResult {
|
|
@@ -9,11 +43,27 @@ export interface OAuthResult {
|
|
|
9
43
|
expiresIn: number;
|
|
10
44
|
scopes: string[];
|
|
11
45
|
}
|
|
46
|
+
/** The scopes to request, plus any service that did not get the access level asked for. */
|
|
47
|
+
export interface ResolvedScopes {
|
|
48
|
+
scopes: string[];
|
|
49
|
+
/**
|
|
50
|
+
* Services asked for as read-only that will still be able to write, because Google
|
|
51
|
+
* offers no read-only scope for them. Always empty when asking for read/write.
|
|
52
|
+
*
|
|
53
|
+
* The caller has to tell the user about these. It is the difference between "you asked
|
|
54
|
+
* for read access and got read access" and "you asked for read access and part of this
|
|
55
|
+
* can still change your data".
|
|
56
|
+
*/
|
|
57
|
+
stillAllowWrites: string[];
|
|
58
|
+
}
|
|
12
59
|
/**
|
|
13
60
|
* Convert comma-separated service names to deduplicated scope URLs.
|
|
14
61
|
* Always includes base scopes (openid, userinfo.email).
|
|
62
|
+
*
|
|
63
|
+
* `access` defaults to 'readwrite', so every existing caller and every account
|
|
64
|
+
* authorized before ADR-202 resolves exactly as it did.
|
|
15
65
|
*/
|
|
16
|
-
export declare function scopesForServices(services: string):
|
|
66
|
+
export declare function scopesForServices(services: string, access?: AccessLevel): ResolvedScopes;
|
|
17
67
|
/**
|
|
18
68
|
* Run a full OAuth2 authorization code flow with a localhost callback server.
|
|
19
69
|
*
|
package/build/accounts/oauth.js
CHANGED
|
@@ -20,6 +20,60 @@ export const SERVICE_SCOPE_MAP = {
|
|
|
20
20
|
'https://www.googleapis.com/auth/meetings.space.readonly',
|
|
21
21
|
'https://www.googleapis.com/auth/meetings.space.settings',
|
|
22
22
|
],
|
|
23
|
+
// manage_contacts reads three separate collections and Google gates each behind its
|
|
24
|
+
// own scope: your saved contacts, the addresses you have only corresponded with, and
|
|
25
|
+
// the organization directory. Two of the three have no write form at all.
|
|
26
|
+
contacts: [
|
|
27
|
+
'https://www.googleapis.com/auth/contacts',
|
|
28
|
+
'https://www.googleapis.com/auth/contacts.other.readonly',
|
|
29
|
+
'https://www.googleapis.com/auth/directory.readonly',
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Service name → READ-ONLY scope URL(s), for accounts authorized with `access: 'read'`.
|
|
34
|
+
*
|
|
35
|
+
* A service is missing from this map when Google offers no read-only scope for it. That
|
|
36
|
+
* is NOT treated as "use the read/write scope and say nothing": someone who asked for
|
|
37
|
+
* read access would get write access without being told. `scopesForServices` reports
|
|
38
|
+
* those services instead, so the person consenting can be told before the browser opens
|
|
39
|
+
* (ADR-202).
|
|
40
|
+
*
|
|
41
|
+
* Every service currently has an entry, so nothing is granted more than was asked for
|
|
42
|
+
* today. The reporting path still exists because the next service added may not have
|
|
43
|
+
* one, and finding that out from a silently broad token is the wrong way to find out.
|
|
44
|
+
*
|
|
45
|
+
* Measured against descriptor.json rather than assumed:
|
|
46
|
+
*
|
|
47
|
+
* - calendar, docs, gmail, tasks — the scope below covers every GET method exposed.
|
|
48
|
+
* - meet — `meetings.space.readonly` authorizes every READ manage_meet exposes: all the
|
|
49
|
+
* conference-record operations, plus getSpace. The tool also creates, updates and ends
|
|
50
|
+
* meeting spaces, and those three need `meetings.space.created` or `.settings`, so a
|
|
51
|
+
* read-only meet account holds the readonly scope alone and Google refuses the writes.
|
|
52
|
+
* That is the mapping working, not a gap in it. Meet was very nearly left out of this
|
|
53
|
+
* map entirely by reading "has no read-only variant" off the scope list instead of off
|
|
54
|
+
* what each operation needs.
|
|
55
|
+
* - drive, sheets — two GET methods and one respectively that no read-only scope covers,
|
|
56
|
+
* so read access there allows less than full access but slightly more than reading.
|
|
57
|
+
* - contacts — only the first of its three scopes has a write form. `contacts.readonly`
|
|
58
|
+
* replaces `contacts`; `contacts.other.readonly` and `directory.readonly` are already
|
|
59
|
+
* read-only and so are identical in both maps. A read-only contacts account reaches
|
|
60
|
+
* every read manage_contacts has and is refused `create` by Google, which is the
|
|
61
|
+
* mapping working.
|
|
62
|
+
*/
|
|
63
|
+
export const SERVICE_SCOPE_MAP_READONLY = {
|
|
64
|
+
gmail: ['https://www.googleapis.com/auth/gmail.readonly'],
|
|
65
|
+
drive: ['https://www.googleapis.com/auth/drive.readonly'],
|
|
66
|
+
calendar: ['https://www.googleapis.com/auth/calendar.readonly'],
|
|
67
|
+
sheets: ['https://www.googleapis.com/auth/spreadsheets.readonly'],
|
|
68
|
+
docs: ['https://www.googleapis.com/auth/documents.readonly'],
|
|
69
|
+
tasks: ['https://www.googleapis.com/auth/tasks.readonly'],
|
|
70
|
+
slides: ['https://www.googleapis.com/auth/presentations.readonly'],
|
|
71
|
+
meet: ['https://www.googleapis.com/auth/meetings.space.readonly'],
|
|
72
|
+
contacts: [
|
|
73
|
+
'https://www.googleapis.com/auth/contacts.readonly',
|
|
74
|
+
'https://www.googleapis.com/auth/contacts.other.readonly',
|
|
75
|
+
'https://www.googleapis.com/auth/directory.readonly',
|
|
76
|
+
],
|
|
23
77
|
};
|
|
24
78
|
const BASE_SCOPES = [
|
|
25
79
|
'openid',
|
|
@@ -30,19 +84,29 @@ export const ALL_SERVICES = Object.keys(SERVICE_SCOPE_MAP).join(',');
|
|
|
30
84
|
/**
|
|
31
85
|
* Convert comma-separated service names to deduplicated scope URLs.
|
|
32
86
|
* Always includes base scopes (openid, userinfo.email).
|
|
87
|
+
*
|
|
88
|
+
* `access` defaults to 'readwrite', so every existing caller and every account
|
|
89
|
+
* authorized before ADR-202 resolves exactly as it did.
|
|
33
90
|
*/
|
|
34
|
-
export function scopesForServices(services) {
|
|
91
|
+
export function scopesForServices(services, access = 'readwrite') {
|
|
35
92
|
const names = services.split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
|
|
36
93
|
const scopes = new Set(BASE_SCOPES);
|
|
94
|
+
const stillAllowWrites = [];
|
|
37
95
|
for (const name of names) {
|
|
38
|
-
const
|
|
39
|
-
if (!
|
|
96
|
+
const readwrite = SERVICE_SCOPE_MAP[name];
|
|
97
|
+
if (!readwrite) {
|
|
40
98
|
throw new Error(`Unknown service: '${name}'. Known: ${Object.keys(SERVICE_SCOPE_MAP).join(', ')}`);
|
|
41
99
|
}
|
|
42
|
-
|
|
100
|
+
// Read access uses the read-only scope where Google offers one. Where it does not,
|
|
101
|
+
// the service keeps its read/write scope AND is reported — see
|
|
102
|
+
// SERVICE_SCOPE_MAP_READONLY.
|
|
103
|
+
const readonly = access === 'read' ? SERVICE_SCOPE_MAP_READONLY[name] : undefined;
|
|
104
|
+
if (access === 'read' && !readonly)
|
|
105
|
+
stillAllowWrites.push(name);
|
|
106
|
+
for (const scope of readonly ?? readwrite)
|
|
43
107
|
scopes.add(scope);
|
|
44
108
|
}
|
|
45
|
-
return [...scopes];
|
|
109
|
+
return { scopes: [...scopes], stillAllowWrites };
|
|
46
110
|
}
|
|
47
111
|
/**
|
|
48
112
|
* Run a full OAuth2 authorization code flow with a localhost callback server.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/accounts/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,eAAe,GAAG,2CAA2C,CAAC;AACpE,MAAM,gBAAgB,GAAG,qCAAqC,CAAC;AAC/D,MAAM,mBAAmB,GAAG,+CAA+C,CAAC;AAE5E,MAAM,gBAAgB,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,YAAY;AAEjD,yCAAyC;AACzC,MAAM,CAAC,MAAM,iBAAiB,GAA6B;IACzD,KAAK,EAAK,CAAC,8CAA8C,CAAC;IAC1D,KAAK,EAAK,CAAC,uCAAuC,CAAC;IACnD,QAAQ,EAAE,CAAC,0CAA0C,CAAC;IACtD,MAAM,EAAI,CAAC,8CAA8C,CAAC;IAC1D,IAAI,EAAM,CAAC,2CAA2C,CAAC;IACvD,KAAK,EAAK,CAAC,uCAAuC,CAAC;IACnD,MAAM,EAAI,CAAC,+CAA+C,CAAC;IAC3D,IAAI,EAAE;QACJ,wDAAwD;QACxD,yDAAyD;QACzD,yDAAyD;KAC1D;CACF,CAAC;AAEF,MAAM,WAAW,GAAG;IAClB,QAAQ;IACR,gDAAgD;CACjD,CAAC;AAEF,kDAAkD;AAClD,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/accounts/oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AccessLevel } from './oauth.js';
|
|
1
2
|
import { type AuthResult } from './auth.js';
|
|
2
3
|
export interface Account {
|
|
3
4
|
email: string;
|
|
@@ -8,4 +9,4 @@ export declare function listAccounts(): Promise<Account[]>;
|
|
|
8
9
|
export declare function getAccount(email: string): Promise<Account | undefined>;
|
|
9
10
|
export declare function addAccount(email: string, category?: Account['category'], description?: string): Promise<Account>;
|
|
10
11
|
export declare function removeAccount(email: string): Promise<void>;
|
|
11
|
-
export declare function authenticateAndAddAccount(clientId: string, clientSecret: string, category?: Account['category'], description?: string): Promise<AuthResult>;
|
|
12
|
+
export declare function authenticateAndAddAccount(clientId: string, clientSecret: string, category?: Account['category'], description?: string, access?: AccessLevel): Promise<AuthResult>;
|
|
@@ -49,8 +49,8 @@ export async function removeAccount(email) {
|
|
|
49
49
|
await writeAccounts(data);
|
|
50
50
|
await removeCredential(email);
|
|
51
51
|
}
|
|
52
|
-
export async function authenticateAndAddAccount(clientId, clientSecret, category = 'personal', description) {
|
|
53
|
-
const result = await authenticateAccount(clientId, clientSecret);
|
|
52
|
+
export async function authenticateAndAddAccount(clientId, clientSecret, category = 'personal', description, access = 'readwrite') {
|
|
53
|
+
const result = await authenticateAccount(clientId, clientSecret, access);
|
|
54
54
|
if (result.status === 'success' && result.account) {
|
|
55
55
|
const existing = await getAccount(result.account);
|
|
56
56
|
if (!existing) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/accounts/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/accounts/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,10 +13,10 @@ operations:
|
|
|
13
13
|
params:
|
|
14
14
|
calendarId:
|
|
15
15
|
type: string
|
|
16
|
-
description: "Calendar ID to
|
|
16
|
+
description: "Calendar ID. Use the `calendars` operation to list available IDs; required for events on shared calendars. Defaults to 'primary' on the event operations (`list`, `get`, `create`, `quickAdd`, `update`, `delete`). On `agenda`, a calendar name or ID to filter to — OMIT it to span all calendars, and do not pass 'primary', which is an API alias rather than an id agenda matches on. On `freebusy`, a comma-separated list of calendar IDs to check IN ADDITION to your own."
|
|
17
17
|
timeMin:
|
|
18
18
|
type: string
|
|
19
|
-
description: "Start of range (ISO 8601)
|
|
19
|
+
description: "Start of range (ISO 8601). On `list`, defaults to today."
|
|
20
20
|
timeMax:
|
|
21
21
|
type: string
|
|
22
22
|
description: "End of range (ISO 8601)"
|
|
@@ -40,7 +40,7 @@ operations:
|
|
|
40
40
|
params:
|
|
41
41
|
calendarId:
|
|
42
42
|
type: string
|
|
43
|
-
description: "
|
|
43
|
+
description: "Calendar ID. Use the `calendars` operation to list available IDs; required for events on shared calendars. Defaults to 'primary' on the event operations (`list`, `get`, `create`, `quickAdd`, `update`, `delete`). On `agenda`, a calendar name or ID to filter to — OMIT it to span all calendars, and do not pass 'primary', which is an API alias rather than an id agenda matches on. On `freebusy`, a comma-separated list of calendar IDs to check IN ADDITION to your own."
|
|
44
44
|
days:
|
|
45
45
|
type: number
|
|
46
46
|
description: "Number of days ahead to show (default: today only)"
|
|
@@ -58,7 +58,7 @@ operations:
|
|
|
58
58
|
params:
|
|
59
59
|
calendarId:
|
|
60
60
|
type: string
|
|
61
|
-
description: "Calendar ID
|
|
61
|
+
description: "Calendar ID. Use the `calendars` operation to list available IDs; required for events on shared calendars. Defaults to 'primary' on the event operations (`list`, `get`, `create`, `quickAdd`, `update`, `delete`). On `agenda`, a calendar name or ID to filter to — OMIT it to span all calendars, and do not pass 'primary', which is an API alias rather than an id agenda matches on. On `freebusy`, a comma-separated list of calendar IDs to check IN ADDITION to your own."
|
|
62
62
|
eventId:
|
|
63
63
|
type: string
|
|
64
64
|
description: "Event ID"
|
|
@@ -74,7 +74,7 @@ operations:
|
|
|
74
74
|
params:
|
|
75
75
|
calendarId:
|
|
76
76
|
type: string
|
|
77
|
-
description: "Calendar ID (
|
|
77
|
+
description: "Calendar ID. Use the `calendars` operation to list available IDs; required for events on shared calendars. Defaults to 'primary' on the event operations (`list`, `get`, `create`, `quickAdd`, `update`, `delete`). On `agenda`, a calendar name or ID to filter to — OMIT it to span all calendars, and do not pass 'primary', which is an API alias rather than an id agenda matches on. On `freebusy`, a comma-separated list of calendar IDs to check IN ADDITION to your own."
|
|
78
78
|
summary:
|
|
79
79
|
type: string
|
|
80
80
|
description: "Event title"
|
|
@@ -95,10 +95,10 @@ operations:
|
|
|
95
95
|
description: "Event location"
|
|
96
96
|
attendees:
|
|
97
97
|
type: string
|
|
98
|
-
description: "Comma-separated attendee
|
|
98
|
+
description: "Comma-separated email addresses. On `update`, whatever you pass REPLACES the existing list — addresses you leave out are removed, and an empty string clears everyone. OMIT the parameter to leave the attendee list untouched while changing other fields. On `freebusy`, the addresses whose availability to check."
|
|
99
99
|
meet:
|
|
100
100
|
type: boolean
|
|
101
|
-
description: "Add a Google Meet video conference link to the
|
|
101
|
+
description: "Add a Google Meet video conference link. On `update`, true adds a link and false REMOVES an existing one; omit it to leave the link as it is."
|
|
102
102
|
|
|
103
103
|
quickAdd:
|
|
104
104
|
type: action
|
|
@@ -107,7 +107,7 @@ operations:
|
|
|
107
107
|
params:
|
|
108
108
|
calendarId:
|
|
109
109
|
type: string
|
|
110
|
-
description: "Calendar ID (
|
|
110
|
+
description: "Calendar ID. Use the `calendars` operation to list available IDs; required for events on shared calendars. Defaults to 'primary' on the event operations (`list`, `get`, `create`, `quickAdd`, `update`, `delete`). On `agenda`, a calendar name or ID to filter to — OMIT it to span all calendars, and do not pass 'primary', which is an API alias rather than an id agenda matches on. On `freebusy`, a comma-separated list of calendar IDs to check IN ADDITION to your own."
|
|
111
111
|
text:
|
|
112
112
|
type: string
|
|
113
113
|
description: "Natural language event description"
|
|
@@ -122,32 +122,32 @@ operations:
|
|
|
122
122
|
params:
|
|
123
123
|
calendarId:
|
|
124
124
|
type: string
|
|
125
|
-
description: "Calendar ID (
|
|
125
|
+
description: "Calendar ID. Use the `calendars` operation to list available IDs; required for events on shared calendars. Defaults to 'primary' on the event operations (`list`, `get`, `create`, `quickAdd`, `update`, `delete`). On `agenda`, a calendar name or ID to filter to — OMIT it to span all calendars, and do not pass 'primary', which is an API alias rather than an id agenda matches on. On `freebusy`, a comma-separated list of calendar IDs to check IN ADDITION to your own."
|
|
126
126
|
eventId:
|
|
127
127
|
type: string
|
|
128
|
-
description: "Event ID
|
|
128
|
+
description: "Event ID"
|
|
129
129
|
required: true
|
|
130
130
|
summary:
|
|
131
131
|
type: string
|
|
132
|
-
description: "
|
|
132
|
+
description: "Event title"
|
|
133
133
|
start:
|
|
134
134
|
type: string
|
|
135
|
-
description: "
|
|
135
|
+
description: "Start time (ISO 8601)"
|
|
136
136
|
end:
|
|
137
137
|
type: string
|
|
138
|
-
description: "
|
|
138
|
+
description: "End time (ISO 8601)"
|
|
139
139
|
description:
|
|
140
140
|
type: string
|
|
141
|
-
description: "
|
|
141
|
+
description: "Event description or notes"
|
|
142
142
|
location:
|
|
143
143
|
type: string
|
|
144
|
-
description: "
|
|
144
|
+
description: "Event location"
|
|
145
145
|
attendees:
|
|
146
146
|
type: string
|
|
147
|
-
description: "Comma-separated
|
|
147
|
+
description: "Comma-separated email addresses. On `update`, whatever you pass REPLACES the existing list — addresses you leave out are removed, and an empty string clears everyone. OMIT the parameter to leave the attendee list untouched while changing other fields. On `freebusy`, the addresses whose availability to check."
|
|
148
148
|
meet:
|
|
149
149
|
type: boolean
|
|
150
|
-
description: "Add a Google Meet video conference link.
|
|
150
|
+
description: "Add a Google Meet video conference link. On `update`, true adds a link and false REMOVES an existing one; omit it to leave the link as it is."
|
|
151
151
|
defaults:
|
|
152
152
|
calendarId: primary
|
|
153
153
|
|
|
@@ -158,10 +158,10 @@ operations:
|
|
|
158
158
|
params:
|
|
159
159
|
calendarId:
|
|
160
160
|
type: string
|
|
161
|
-
description: "Calendar ID (
|
|
161
|
+
description: "Calendar ID. Use the `calendars` operation to list available IDs; required for events on shared calendars. Defaults to 'primary' on the event operations (`list`, `get`, `create`, `quickAdd`, `update`, `delete`). On `agenda`, a calendar name or ID to filter to — OMIT it to span all calendars, and do not pass 'primary', which is an API alias rather than an id agenda matches on. On `freebusy`, a comma-separated list of calendar IDs to check IN ADDITION to your own."
|
|
162
162
|
eventId:
|
|
163
163
|
type: string
|
|
164
|
-
description: "Event ID
|
|
164
|
+
description: "Event ID"
|
|
165
165
|
required: true
|
|
166
166
|
defaults:
|
|
167
167
|
calendarId: primary
|
|
@@ -180,7 +180,7 @@ operations:
|
|
|
180
180
|
params:
|
|
181
181
|
timeMin:
|
|
182
182
|
type: string
|
|
183
|
-
description: "Start of range (ISO 8601)"
|
|
183
|
+
description: "Start of range (ISO 8601). On `list`, defaults to today."
|
|
184
184
|
required: true
|
|
185
185
|
timeMax:
|
|
186
186
|
type: string
|
|
@@ -188,7 +188,7 @@ operations:
|
|
|
188
188
|
required: true
|
|
189
189
|
attendees:
|
|
190
190
|
type: string
|
|
191
|
-
description: "Comma-separated email addresses to
|
|
191
|
+
description: "Comma-separated email addresses. On `update`, whatever you pass REPLACES the existing list — addresses you leave out are removed, and an empty string clears everyone. OMIT the parameter to leave the attendee list untouched while changing other fields. On `freebusy`, the addresses whose availability to check."
|
|
192
192
|
calendarId:
|
|
193
193
|
type: string
|
|
194
|
-
description: "
|
|
194
|
+
description: "Calendar ID. Use the `calendars` operation to list available IDs; required for events on shared calendars. Defaults to 'primary' on the event operations (`list`, `get`, `create`, `quickAdd`, `update`, `delete`). On `agenda`, a calendar name or ID to filter to — OMIT it to span all calendars, and do not pass 'primary', which is an API alias rather than an id agenda matches on. On `freebusy`, a comma-separated list of calendar IDs to check IN ADDITION to your own."
|