@aaronsb/google-workspace-mcp 3.0.0 → 4.0.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.
Files changed (145) hide show
  1. package/LICENSE +201 -21
  2. package/LICENSE-MIT +21 -0
  3. package/NOTICE +24 -0
  4. package/README.md +71 -52
  5. package/build/accounts/auth.d.ts +1 -1
  6. package/build/accounts/auth.js +1 -1
  7. package/build/accounts/oauth.js +3 -3
  8. package/build/accounts/oauth.js.map +1 -1
  9. package/build/accounts/token-service.js +1 -1
  10. package/build/accounts/token-service.js.map +1 -1
  11. package/build/coverage/analyze.d.ts +1 -1
  12. package/build/coverage/analyze.js +6 -4
  13. package/build/coverage/analyze.js.map +1 -1
  14. package/build/coverage/baseline.js +37 -20
  15. package/build/coverage/baseline.js.map +1 -1
  16. package/build/coverage/compare.d.ts +1 -1
  17. package/build/coverage/compare.js +19 -10
  18. package/build/coverage/compare.js.map +1 -1
  19. package/build/coverage/discover.d.ts +5 -5
  20. package/build/coverage/discover.js +71 -155
  21. package/build/coverage/discover.js.map +1 -1
  22. package/build/coverage/report.js +3 -3
  23. package/build/coverage/report.js.map +1 -1
  24. package/build/coverage/types.d.ts +19 -4
  25. package/build/executor/index.d.ts +0 -3
  26. package/build/executor/index.js +1 -2
  27. package/build/executor/index.js.map +1 -1
  28. package/build/factory/defaults.js +30 -4
  29. package/build/factory/defaults.js.map +1 -1
  30. package/build/factory/generator.d.ts +10 -2
  31. package/build/factory/generator.js +54 -69
  32. package/build/factory/generator.js.map +1 -1
  33. package/build/factory/manifest/README.md +4 -3
  34. package/build/factory/manifest/calendar.yaml +1 -11
  35. package/build/factory/manifest/docs.yaml +15 -6
  36. package/build/factory/manifest/drive.yaml +1 -5
  37. package/build/factory/manifest/gmail.yaml +9 -24
  38. package/build/factory/manifest/meet.yaml +1 -1
  39. package/build/factory/manifest/sheets.yaml +2 -5
  40. package/build/factory/manifest/tasks.yaml +40 -2
  41. package/build/factory/patches.js +2 -0
  42. package/build/factory/patches.js.map +1 -1
  43. package/build/factory/safety.js +4 -4
  44. package/build/factory/safety.js.map +1 -1
  45. package/build/factory/types.d.ts +16 -15
  46. package/build/google/client.d.ts +45 -0
  47. package/build/google/client.js +232 -0
  48. package/build/google/client.js.map +1 -0
  49. package/build/google/descriptor.d.ts +40 -0
  50. package/build/google/descriptor.js +37 -0
  51. package/build/google/descriptor.js.map +1 -0
  52. package/build/google/descriptor.json +5271 -0
  53. package/build/google/errors.d.ts +45 -0
  54. package/build/google/errors.js +44 -0
  55. package/build/google/errors.js.map +1 -0
  56. package/build/google/methods.d.ts +37 -0
  57. package/build/google/methods.js +13 -0
  58. package/build/google/methods.js.map +1 -0
  59. package/build/index.js +3 -3
  60. package/build/index.js.map +1 -1
  61. package/build/node-floor.js +1 -1
  62. package/build/node-floor.js.map +1 -1
  63. package/build/server/formatting/markdown.d.ts +1 -1
  64. package/build/server/formatting/markdown.js +1 -1
  65. package/build/server/formatting/next-steps.js +1 -1
  66. package/build/server/formatting/next-steps.js.map +1 -1
  67. package/build/server/handlers/accounts.js +2 -2
  68. package/build/server/handlers/accounts.js.map +1 -1
  69. package/build/server/scratchpad/adapters/import-doc.js +15 -13
  70. package/build/server/scratchpad/adapters/import-doc.js.map +1 -1
  71. package/build/server/scratchpad/adapters/import-drive.js +16 -11
  72. package/build/server/scratchpad/adapters/import-drive.js.map +1 -1
  73. package/build/server/scratchpad/adapters/import-email.js +3 -15
  74. package/build/server/scratchpad/adapters/import-email.js.map +1 -1
  75. package/build/server/scratchpad/adapters/import-meet.js +5 -17
  76. package/build/server/scratchpad/adapters/import-meet.js.map +1 -1
  77. package/build/server/scratchpad/adapters/import-sheet.js +5 -6
  78. package/build/server/scratchpad/adapters/import-sheet.js.map +1 -1
  79. package/build/server/scratchpad/adapters/send-calendar.js +18 -13
  80. package/build/server/scratchpad/adapters/send-calendar.js.map +1 -1
  81. package/build/server/scratchpad/adapters/send-doc.js +22 -17
  82. package/build/server/scratchpad/adapters/send-doc.js.map +1 -1
  83. package/build/server/scratchpad/adapters/send-email-draft.d.ts +1 -1
  84. package/build/server/scratchpad/adapters/send-email-draft.js +17 -25
  85. package/build/server/scratchpad/adapters/send-email-draft.js.map +1 -1
  86. package/build/server/scratchpad/adapters/send-email.d.ts +2 -2
  87. package/build/server/scratchpad/adapters/send-email.js +21 -25
  88. package/build/server/scratchpad/adapters/send-email.js.map +1 -1
  89. package/build/server/scratchpad/adapters/send-sheet.js +10 -10
  90. package/build/server/scratchpad/adapters/send-sheet.js.map +1 -1
  91. package/build/server/scratchpad/adapters/send-task.js +9 -8
  92. package/build/server/scratchpad/adapters/send-task.js.map +1 -1
  93. package/build/server/scratchpad/handler.js +22 -28
  94. package/build/server/scratchpad/handler.js.map +1 -1
  95. package/build/server/scratchpad/manager.d.ts +1 -1
  96. package/build/server/server.js +13 -10
  97. package/build/server/server.js.map +1 -1
  98. package/build/server/session/tracker.js +21 -25
  99. package/build/server/session/tracker.js.map +1 -1
  100. package/build/server/tools.d.ts +1 -1
  101. package/build/server/tools.js +3 -3
  102. package/build/server/tools.js.map +1 -1
  103. package/build/services/calendar/patch.js +178 -68
  104. package/build/services/calendar/patch.js.map +1 -1
  105. package/build/services/docs/patch.d.ts +5 -3
  106. package/build/services/docs/patch.js +89 -19
  107. package/build/services/docs/patch.js.map +1 -1
  108. package/build/services/drive/patch.d.ts +1 -1
  109. package/build/services/drive/patch.js +115 -143
  110. package/build/services/drive/patch.js.map +1 -1
  111. package/build/services/gmail/attachments.js +10 -15
  112. package/build/services/gmail/attachments.js.map +1 -1
  113. package/build/services/gmail/mail.d.ts +34 -0
  114. package/build/services/gmail/mail.js +245 -0
  115. package/build/services/gmail/mail.js.map +1 -0
  116. package/build/services/gmail/mime.d.ts +45 -4
  117. package/build/services/gmail/mime.js +138 -4
  118. package/build/services/gmail/mime.js.map +1 -1
  119. package/build/services/gmail/patch.js +69 -83
  120. package/build/services/gmail/patch.js.map +1 -1
  121. package/build/services/meet/patch.js +24 -31
  122. package/build/services/meet/patch.js.map +1 -1
  123. package/build/services/sheets/patch.js +30 -35
  124. package/build/services/sheets/patch.js.map +1 -1
  125. package/build/services/tasks/patch.d.ts +18 -0
  126. package/build/services/tasks/patch.js +37 -0
  127. package/build/services/tasks/patch.js.map +1 -0
  128. package/build/version.d.ts +1 -1
  129. package/build/version.js +1 -1
  130. package/package.json +11 -6
  131. package/build/executor/errors.d.ts +0 -15
  132. package/build/executor/errors.js +0 -37
  133. package/build/executor/errors.js.map +0 -1
  134. package/build/executor/gws.d.ts +0 -26
  135. package/build/executor/gws.js +0 -197
  136. package/build/executor/gws.js.map +0 -1
  137. package/build/server/handlers/calendar.d.ts +0 -2
  138. package/build/server/handlers/calendar.js +0 -97
  139. package/build/server/handlers/calendar.js.map +0 -1
  140. package/build/server/handlers/drive.d.ts +0 -2
  141. package/build/server/handlers/drive.js +0 -58
  142. package/build/server/handlers/drive.js.map +0 -1
  143. package/build/server/handlers/email.d.ts +0 -2
  144. package/build/server/handlers/email.js +0 -119
  145. package/build/server/handlers/email.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  tool_name: manage_tasks
2
2
  description: "Manage task lists and tasks in Google Tasks."
3
3
  requires_email: true
4
- gws_service: tasks
4
+ google_service: tasks
5
5
  operations:
6
6
 
7
7
  # --- Task lists ---
@@ -22,10 +22,18 @@ operations:
22
22
  required: true
23
23
  maps_to: tasklist
24
24
 
25
+ # A TaskList's only meaningful field is its title, and it rides in the BODY —
26
+ # tasklists.insert declares no parameters. Without it this could only ever create
27
+ # nameless task lists, and did so without complaint.
25
28
  createTaskList:
26
29
  type: action
27
30
  description: "create a new task list"
28
31
  resource: tasklists.insert
32
+ params:
33
+ title:
34
+ type: string
35
+ description: "Task list name"
36
+ required: true
29
37
 
30
38
  deleteTaskList:
31
39
  type: action
@@ -75,6 +83,10 @@ operations:
75
83
  required: true
76
84
  maps_to: task
77
85
 
86
+ # title / notes / due are BODY fields (the Task resource). tasks.insert declares only
87
+ # `tasklist` (path) and `parent`/`previous` (query), so anything else goes in the body.
88
+ # Without them, `create` sent an empty Task and produced a BLANK task — no title, no
89
+ # content, no error. A titleless task is not a degraded task; it is a useless one.
78
90
  create:
79
91
  type: action
80
92
  description: "create a new task"
@@ -85,10 +97,23 @@ operations:
85
97
  description: "Task list ID"
86
98
  required: true
87
99
  maps_to: tasklist
100
+ title:
101
+ type: string
102
+ description: "Task title"
103
+ required: true
104
+ notes:
105
+ type: string
106
+ description: "Task notes / details"
107
+ due:
108
+ type: string
109
+ description: "Due date (RFC 3339, e.g. 2026-07-20T00:00:00.000Z — Google stores the date, not the time)"
88
110
 
111
+ # An `update` with no updatable fields could only ever PATCH an empty body, which
112
+ # Google Tasks answers with a 500 "Internal error encountered". So this operation did
113
+ # not merely fail to update — it failed EVERY time, and blamed Google while doing it.
89
114
  update:
90
115
  type: action
91
- description: "update a task (patch semantics)"
116
+ description: "update a task (patch semantics — only the fields you pass are changed)"
92
117
  resource: tasks.patch
93
118
  params:
94
119
  taskListId:
@@ -101,6 +126,19 @@ operations:
101
126
  description: "Task ID"
102
127
  required: true
103
128
  maps_to: task
129
+ title:
130
+ type: string
131
+ description: "New task title"
132
+ notes:
133
+ type: string
134
+ description: "New task notes / details"
135
+ due:
136
+ type: string
137
+ description: "New due date (RFC 3339)"
138
+ status:
139
+ type: string
140
+ description: "Task status"
141
+ enum: [needsAction, completed]
104
142
 
105
143
  complete:
106
144
  type: action
@@ -8,6 +8,7 @@ import { drivePatch } from '../services/drive/patch.js';
8
8
  import { docsPatch } from '../services/docs/patch.js';
9
9
  import { meetPatch } from '../services/meet/patch.js';
10
10
  import { sheetsPatch } from '../services/sheets/patch.js';
11
+ import { tasksPatch } from '../services/tasks/patch.js';
11
12
  export const patches = {
12
13
  gmail: gmailPatch,
13
14
  calendar: calendarPatch,
@@ -15,5 +16,6 @@ export const patches = {
15
16
  docs: docsPatch,
16
17
  meet: meetPatch,
17
18
  sheets: sheetsPatch,
19
+ tasks: tasksPatch,
18
20
  };
19
21
  //# sourceMappingURL=patches.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"patches.js","sourceRoot":"","sources":["../../src/factory/patches.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAG1D,MAAM,CAAC,MAAM,OAAO,GAAiC;IACnD,KAAK,EAAE,UAAU;IACjB,QAAQ,EAAE,aAAa;IACvB,KAAK,EAAE,UAAU;IACjB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,WAAW;CACpB,CAAC"}
1
+ {"version":3,"file":"patches.js","sourceRoot":"","sources":["../../src/factory/patches.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAGxD,MAAM,CAAC,MAAM,OAAO,GAAiC;IACnD,KAAK,EAAE,UAAU;IACjB,QAAQ,EAAE,aAAa;IACvB,KAAK,EAAE,UAAU;IACjB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,WAAW;IACnB,KAAK,EAAE,UAAU;CAClB,CAAC"}
@@ -113,7 +113,7 @@ export const auditLog = {
113
113
  applies: () => true,
114
114
  evaluate: (_args, ctx, service) => {
115
115
  if (!isReadOperation(ctx.operation)) {
116
- process.stderr.write(`[gws-mcp] AUDIT: ${service}.${ctx.operation} account=${ctx.account} ` +
116
+ process.stderr.write(`[google-workspace-mcp] AUDIT: ${service}.${ctx.operation} account=${ctx.account} ` +
117
117
  `args=${JSON.stringify(ctx.params)}\n`);
118
118
  }
119
119
  return { action: 'allow' };
@@ -126,7 +126,7 @@ let activePolicies = [];
126
126
  export function configurePolicies(policies) {
127
127
  activePolicies = policies;
128
128
  if (policies.length > 0) {
129
- process.stderr.write(`[gws-mcp] safety: ${policies.length} policy(ies) active: ` +
129
+ process.stderr.write(`[google-workspace-mcp] safety: ${policies.length} policy(ies) active: ` +
130
130
  `${policies.map(p => p.name).join(', ')}\n`);
131
131
  }
132
132
  }
@@ -144,11 +144,11 @@ export function evaluatePolicies(args, ctx, service) {
144
144
  continue;
145
145
  const result = policy.evaluate(args, ctx, service);
146
146
  if (result.action === 'block') {
147
- process.stderr.write(`[gws-mcp] safety: BLOCKED ${service}.${ctx.operation} by ${policy.name}: ${result.reason}\n`);
147
+ process.stderr.write(`[google-workspace-mcp] safety: BLOCKED ${service}.${ctx.operation} by ${policy.name}: ${result.reason}\n`);
148
148
  return result;
149
149
  }
150
150
  if (result.action === 'downgrade' && result.replacementArgs) {
151
- process.stderr.write(`[gws-mcp] safety: DOWNGRADED ${service}.${ctx.operation} by ${policy.name}: ${result.reason}\n`);
151
+ process.stderr.write(`[google-workspace-mcp] safety: DOWNGRADED ${service}.${ctx.operation} by ${policy.name}: ${result.reason}\n`);
152
152
  return result;
153
153
  }
154
154
  }
@@ -1 +1 @@
1
- {"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/factory/safety.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/factory/safety.ts"],"names":[],"mappings":"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"}
@@ -10,19 +10,19 @@ export interface ParamDef {
10
10
  required?: boolean;
11
11
  default?: string | number | boolean;
12
12
  max?: number;
13
- /** Maps this param name to a different key in the gws --params JSON. */
13
+ /** Maps this param name to a different key in the params sent to Google. */
14
14
  maps_to?: string;
15
15
  enum?: string[];
16
16
  /**
17
17
  * If true, the param is for the formatter/handler only and is NOT forwarded
18
- * to the gws CLI. Used for client-side controls like `bodyFormat` (ADR-305)
18
+ * to Google. Used for client-side controls like `bodyFormat` (ADR-305)
19
19
  * that affect rendering, not the API call itself.
20
20
  */
21
21
  client_only?: boolean;
22
22
  }
23
23
  /** Hydration config — fetch detail for each item in a list result. */
24
24
  export interface HydrationDef {
25
- /** gws resource path for the detail call (e.g. "users.messages.get"). */
25
+ /** Google resource path for the detail call (e.g. "users.messages.get"). */
26
26
  resource: string;
27
27
  /** Format parameter passed to the detail call. */
28
28
  format?: string;
@@ -34,20 +34,16 @@ export interface OperationDef {
34
34
  /** Categorizes the operation for default formatting. */
35
35
  type: 'list' | 'detail' | 'action';
36
36
  description: string;
37
- /** gws resource path (e.g. "users.messages.list"). */
37
+ /** Google resource path (e.g. "users.messages.list"). */
38
38
  resource?: string;
39
- /** gws helper shorthand (e.g. "+triage", "+send"). */
40
- helper?: string;
41
39
  /** Named parameters the caller can provide. */
42
40
  params?: Record<string, ParamDef>;
43
- /** Default values merged into the gws --params JSON. */
41
+ /** Default values merged into the params sent to Google. */
44
42
  defaults?: Record<string, unknown>;
45
43
  /** Post-fetch hydration (list operations only). */
46
44
  hydration?: HydrationDef;
47
- /** Fields to extract from the gws response for the result. */
45
+ /** Fields to extract from Google's response for the result. */
48
46
  fields?: string;
49
- /** CLI-style args instead of --params JSON (for helpers). */
50
- cli_args?: Record<string, string>;
51
47
  }
52
48
  /** A service declaration in the manifest. */
53
49
  export interface ServiceDef {
@@ -55,8 +51,8 @@ export interface ServiceDef {
55
51
  description: string;
56
52
  /** Whether this service requires an email account param. */
57
53
  requires_email: boolean;
58
- /** The gws service name (e.g. "gmail", "calendar", "drive"). */
59
- gws_service: string;
54
+ /** The Google service name (e.g. "gmail", "calendar", "drive"). */
55
+ google_service: string;
60
56
  operations: Record<string, OperationDef>;
61
57
  }
62
58
  /** Top-level manifest shape. */
@@ -69,9 +65,14 @@ export interface PatchContext {
69
65
  params: Record<string, unknown>;
70
66
  account: string;
71
67
  }
72
- /** A patch hook that runs after arg construction, before gws execution. */
73
- export type BeforeExecuteHook = (args: string[], ctx: PatchContext) => Promise<string[]> | string[];
74
- /** A patch hook that runs after gws returns, before formatting. */
68
+ /**
69
+ * A patch hook that runs after the manifest's param mapping, before the call.
70
+ *
71
+ * It receives the PARAMS Google will be sent. Hooks operate on the param object
72
+ * directly — never on a serialised command line. See ADR-103.
73
+ */
74
+ export type BeforeExecuteHook = (params: Record<string, unknown>, ctx: PatchContext) => Promise<Record<string, unknown>> | Record<string, unknown>;
75
+ /** A patch hook that runs after Google returns, before formatting. */
75
76
  export type AfterExecuteHook = (result: unknown, ctx: PatchContext) => Promise<unknown> | unknown;
76
77
  /** A formatter override for a specific operation type. */
77
78
  export type FormatHook = (data: unknown, ctx: PatchContext) => HandlerResponse;
@@ -0,0 +1,45 @@
1
+ import { type ApiDescriptor } from './descriptor.js';
2
+ import type { GoogleService, ServiceMethods } from './methods.js';
3
+ export interface CallOptions {
4
+ /** Account email — the token is minted for this identity. */
5
+ account: string;
6
+ descriptor?: ApiDescriptor;
7
+ fetchImpl?: typeof fetch;
8
+ }
9
+ export interface BuiltRequest {
10
+ url: string;
11
+ method: string;
12
+ body?: Record<string, unknown>;
13
+ }
14
+ /** Pure: descriptor + params -> the request. No I/O, so it is testable offline. */
15
+ export declare function buildRequest(descriptor: ApiDescriptor, service: string, resourcePath: string, params?: Record<string, unknown>): BuiltRequest;
16
+ /**
17
+ * Call a Google API method. Returns RAW Google JSON — no envelope, no reshaping.
18
+ * Throws GoogleApiError carrying Google's real error body.
19
+ */
20
+ export declare function call<S extends GoogleService>(service: S, resourcePath: ServiceMethods[S], params: Record<string, unknown>, options: CallOptions): Promise<unknown>;
21
+ /**
22
+ * Download media to disk.
23
+ *
24
+ * STREAMED, deliberately. The bytes go from the socket to the file and are never a
25
+ * string at all. Never buffer a download through an in-memory string: accumulating
26
+ * the whole response and JSON.parse-ing it turns a 30 MB attachment into a ~40 MB
27
+ * string, then an object, then a Buffer — uncapped, for every download.
28
+ */
29
+ export declare function download<S extends GoogleService>(service: S, resourcePath: ServiceMethods[S], params: Record<string, unknown>, outputPath: string, options: CallOptions): Promise<string>;
30
+ export interface UploadOptions extends CallOptions {
31
+ media: Buffer;
32
+ contentType: string;
33
+ metadata?: Record<string, unknown>;
34
+ /** Non-final chunks must be a multiple of 256 KiB. */
35
+ chunkSize?: number;
36
+ }
37
+ /**
38
+ * Resumable, chunked media upload.
39
+ *
40
+ * The descriptor carries the upload paths for both protocols because Discovery
41
+ * DECLARES them. Verified live (ADR-103 item 4): a 25 MB attachment — 34.2 MB as
42
+ * RFC822, 93% of Google's declared 36,700,160-byte cap — uploaded in 5 chunks and
43
+ * read back byte-for-byte identical.
44
+ */
45
+ export declare function upload<S extends GoogleService>(service: S, resourcePath: ServiceMethods[S], params: Record<string, unknown>, options: UploadOptions): Promise<unknown>;
@@ -0,0 +1,232 @@
1
+ /**
2
+ * The Google API client.
3
+ *
4
+ * The whole of a resource operation: get a token, make the call, hand back the JSON.
5
+ *
6
+ * LOAD-BEARING CONSTRAINT — this layer has NO OPINIONS. It never reshapes, never
7
+ * "fixes", never fills in. It returns exactly what Google returned. Interpretation
8
+ * happens ABOVE it, in the layer we already own and aim at the MCP contract
9
+ * (patches / formatters / next-steps). The moment this file gets helpful, it
10
+ * becomes something that can be subtly wrong in a way no test catches — the exact
11
+ * defect class ADR-101 spent six review rounds learning to fear.
12
+ *
13
+ * Everything here is a consequence of something the DESCRIPTOR said. Where a rule
14
+ * looks arbitrary, it is not: it is a fact we learned by being wrong first, live,
15
+ * against Google (ADR-103, item 2).
16
+ *
17
+ * See ADR-103.
18
+ */
19
+ import { createWriteStream } from 'node:fs';
20
+ import { mkdir } from 'node:fs/promises';
21
+ import { dirname } from 'node:path';
22
+ import { Readable } from 'node:stream';
23
+ import { pipeline } from 'node:stream/promises';
24
+ import { getAccessToken } from '../accounts/token-service.js';
25
+ import { GoogleApiError } from './errors.js';
26
+ import { loadDescriptor } from './descriptor.js';
27
+ function resolve(descriptor, service, resourcePath) {
28
+ const svc = descriptor.services[service];
29
+ if (!svc)
30
+ throw new Error(`descriptor has no service '${service}'`);
31
+ const method = svc.methods[resourcePath];
32
+ if (!method)
33
+ throw new Error(`descriptor has no method '${service}.${resourcePath}'`);
34
+ return { svc, method };
35
+ }
36
+ /**
37
+ * Expand a path template.
38
+ *
39
+ * `{+var}` is RFC 6570 RESERVED expansion — reserved characters, notably `/`,
40
+ * must NOT be percent-encoded. Meet's identifiers ARE paths
41
+ * ("conferenceRecords/abc"), so encoding that slash to %2F 404s every Meet
42
+ * sub-resource operation. The `+` is the descriptor telling us this. Honour it.
43
+ */
44
+ function expandPath(template, pathParams) {
45
+ return template.replace(/\{(\+?)([^}]+)\}/g, (_m, reserved, name) => {
46
+ if (!(name in pathParams))
47
+ throw new Error(`missing required path param '${name}'`);
48
+ const raw = String(pathParams[name]);
49
+ return reserved
50
+ ? raw.split('/').map(encodeURIComponent).join('/')
51
+ : encodeURIComponent(raw);
52
+ });
53
+ }
54
+ /**
55
+ * Split params into path / query / body by what the descriptor DECLARES.
56
+ *
57
+ * Global parameters (`fields`, `alt`, `quotaUser`, `prettyPrint`) are declared
58
+ * ONCE at the document root, not per method. A dispatcher that consults only the
59
+ * method's parameters cannot place `fields`, drops it into the body, and a GET
60
+ * silently discards it — which is exactly how drive.listComments died with
61
+ * "The 'fields' parameter is required". Merge both; the method wins on conflict.
62
+ */
63
+ function splitParams(svc, method, params) {
64
+ const declared = { ...svc.globalParameters, ...method.parameters };
65
+ const path = {};
66
+ const query = {};
67
+ const body = {};
68
+ for (const [key, value] of Object.entries(params)) {
69
+ if (value === undefined || value === null)
70
+ continue;
71
+ const location = declared[key]?.location;
72
+ if (location === 'path')
73
+ path[key] = value;
74
+ else if (location === 'query')
75
+ query[key] = value;
76
+ else
77
+ body[key] = value; // undeclared -> request body; Google validates it, not us
78
+ }
79
+ return { path, query, body };
80
+ }
81
+ function applyQuery(url, query) {
82
+ for (const [key, value] of Object.entries(query)) {
83
+ if (Array.isArray(value))
84
+ value.forEach((v) => url.searchParams.append(key, String(v)));
85
+ else
86
+ url.searchParams.set(key, String(value));
87
+ }
88
+ return url;
89
+ }
90
+ /** Pure: descriptor + params -> the request. No I/O, so it is testable offline. */
91
+ export function buildRequest(descriptor, service, resourcePath, params = {}) {
92
+ const { svc, method } = resolve(descriptor, service, resourcePath);
93
+ const { path, query, body } = splitParams(svc, method, params);
94
+ const base = svc.rootUrl.replace(/\/$/, '') + '/' + svc.servicePath.replace(/^\//, '');
95
+ const url = applyQuery(new URL((base.replace(/\/$/, '') + '/' + expandPath(method.path, path)).replace(/\/+$/, '')), query);
96
+ const hasBody = Object.keys(body).length > 0 && method.httpMethod !== 'GET';
97
+ return { url: url.toString(), method: method.httpMethod, body: hasBody ? body : undefined };
98
+ }
99
+ function parseJson(text) {
100
+ if (!text)
101
+ return {};
102
+ try {
103
+ return JSON.parse(text);
104
+ }
105
+ catch {
106
+ return { error: { message: text.slice(0, 300) } };
107
+ }
108
+ }
109
+ /**
110
+ * Call a Google API method. Returns RAW Google JSON — no envelope, no reshaping.
111
+ * Throws GoogleApiError carrying Google's real error body.
112
+ */
113
+ export async function call(service, resourcePath, params, options) {
114
+ const descriptor = options.descriptor ?? await loadDescriptor();
115
+ const doFetch = options.fetchImpl ?? fetch;
116
+ const request = buildRequest(descriptor, service, resourcePath, params);
117
+ const token = await getAccessToken(options.account);
118
+ const response = await doFetch(request.url, {
119
+ method: request.method,
120
+ headers: {
121
+ Authorization: `Bearer ${token}`,
122
+ ...(request.body ? { 'Content-Type': 'application/json' } : {}),
123
+ },
124
+ ...(request.body ? { body: JSON.stringify(request.body) } : {}),
125
+ });
126
+ const text = await response.text();
127
+ const json = parseJson(text);
128
+ if (!response.ok) {
129
+ throw new GoogleApiError(response.status, json, {
130
+ url: request.url,
131
+ method: request.method,
132
+ });
133
+ }
134
+ return json;
135
+ }
136
+ /**
137
+ * Download media to disk.
138
+ *
139
+ * STREAMED, deliberately. The bytes go from the socket to the file and are never a
140
+ * string at all. Never buffer a download through an in-memory string: accumulating
141
+ * the whole response and JSON.parse-ing it turns a 30 MB attachment into a ~40 MB
142
+ * string, then an object, then a Buffer — uncapped, for every download.
143
+ */
144
+ export async function download(service, resourcePath, params, outputPath, options) {
145
+ const descriptor = options.descriptor ?? await loadDescriptor();
146
+ const doFetch = options.fetchImpl ?? fetch;
147
+ const request = buildRequest(descriptor, service, resourcePath, params);
148
+ const token = await getAccessToken(options.account);
149
+ const response = await doFetch(request.url, {
150
+ method: request.method,
151
+ headers: { Authorization: `Bearer ${token}` },
152
+ });
153
+ if (!response.ok) {
154
+ const json = parseJson(await response.text());
155
+ throw new GoogleApiError(response.status, json, {
156
+ url: request.url,
157
+ method: request.method,
158
+ });
159
+ }
160
+ if (!response.body)
161
+ throw new Error(`no response body for ${service}.${resourcePath}`);
162
+ await mkdir(dirname(outputPath), { recursive: true });
163
+ await pipeline(Readable.fromWeb(response.body), createWriteStream(outputPath));
164
+ return outputPath;
165
+ }
166
+ /**
167
+ * Resumable, chunked media upload.
168
+ *
169
+ * The descriptor carries the upload paths for both protocols because Discovery
170
+ * DECLARES them. Verified live (ADR-103 item 4): a 25 MB attachment — 34.2 MB as
171
+ * RFC822, 93% of Google's declared 36,700,160-byte cap — uploaded in 5 chunks and
172
+ * read back byte-for-byte identical.
173
+ */
174
+ export async function upload(service, resourcePath, params, options) {
175
+ const descriptor = options.descriptor ?? await loadDescriptor();
176
+ const doFetch = options.fetchImpl ?? fetch;
177
+ const { svc, method } = resolve(descriptor, service, resourcePath);
178
+ if (!method.mediaUpload)
179
+ throw new Error(`${service}.${resourcePath} does not support media upload`);
180
+ // Google DECLARES the ceiling. Refusing locally beats a confusing 400 from a
181
+ // 35 MB request that already crossed the wire.
182
+ const max = Number(method.mediaUpload.maxSize);
183
+ if (max && options.media.length > max) {
184
+ throw new Error(`${service}.${resourcePath}: payload is ${options.media.length} bytes; ` +
185
+ `Google's declared limit is ${max} bytes`);
186
+ }
187
+ const token = await getAccessToken(options.account);
188
+ const { path, query } = splitParams(svc, method, params);
189
+ const uploadPath = method.mediaUpload.resumable ?? method.mediaUpload.simple;
190
+ if (!uploadPath)
191
+ throw new Error(`${service}.${resourcePath} declares no upload protocol`);
192
+ const initiateUrl = applyQuery(new URL(expandPath(uploadPath, path), svc.rootUrl), { ...query, uploadType: 'resumable' }).toString();
193
+ const initiate = await doFetch(initiateUrl, {
194
+ method: method.httpMethod,
195
+ headers: {
196
+ Authorization: `Bearer ${token}`,
197
+ 'Content-Type': 'application/json; charset=UTF-8',
198
+ 'X-Upload-Content-Type': options.contentType,
199
+ 'X-Upload-Content-Length': String(options.media.length),
200
+ },
201
+ body: JSON.stringify(options.metadata ?? {}),
202
+ });
203
+ if (!initiate.ok) {
204
+ const json = parseJson(await initiate.text());
205
+ throw new GoogleApiError(initiate.status, json, { url: initiateUrl, method: method.httpMethod });
206
+ }
207
+ const session = initiate.headers.get('location');
208
+ if (!session)
209
+ throw new Error('resumable upload: initiate returned no Location header');
210
+ const chunkSize = options.chunkSize ?? 8 * 1024 * 1024;
211
+ let offset = 0;
212
+ while (offset < options.media.length) {
213
+ const end = Math.min(offset + chunkSize, options.media.length);
214
+ const response = await doFetch(session, {
215
+ method: 'PUT',
216
+ headers: { 'Content-Range': `bytes ${offset}-${end - 1}/${options.media.length}` },
217
+ body: options.media.subarray(offset, end),
218
+ });
219
+ // 308 "Resume Incomplete" is the protocol working, not an error.
220
+ if (response.status === 308) {
221
+ offset = end;
222
+ continue;
223
+ }
224
+ const text = await response.text();
225
+ if (!response.ok) {
226
+ throw new GoogleApiError(response.status, parseJson(text), { url: session, method: 'PUT' });
227
+ }
228
+ return parseJson(text);
229
+ }
230
+ throw new Error('resumable upload: media consumed without a terminal response');
231
+ }
232
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/google/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ export interface ApiParam {
2
+ location: 'path' | 'query';
3
+ required?: boolean;
4
+ repeated?: boolean;
5
+ }
6
+ export interface ApiMediaUpload {
7
+ maxSize?: string;
8
+ accept?: string[];
9
+ simple?: string;
10
+ resumable?: string;
11
+ }
12
+ export interface ApiMethod {
13
+ path: string;
14
+ httpMethod: string;
15
+ parameters: Record<string, ApiParam>;
16
+ scopes?: string[];
17
+ supportsMediaDownload?: boolean;
18
+ mediaUpload?: ApiMediaUpload;
19
+ }
20
+ export interface ApiService {
21
+ version: string;
22
+ rootUrl: string;
23
+ servicePath: string;
24
+ discoveryUrl: string;
25
+ /** `fields`, `alt`, `quotaUser`… declared once at the document root, not per method. */
26
+ globalParameters: Record<string, ApiParam>;
27
+ methods: Record<string, ApiMethod>;
28
+ }
29
+ export interface ApiDescriptor {
30
+ generatedFrom: string;
31
+ services: Record<string, ApiService>;
32
+ }
33
+ /**
34
+ * Load the descriptor. Resolved as a sibling of this module, which makes it work
35
+ * under `src/` (vitest) and under `build/` (the shipped server) alike — the same
36
+ * trick `loadManifest()` uses, and the reason `npx` works.
37
+ */
38
+ export declare function loadDescriptor(): Promise<ApiDescriptor>;
39
+ /** Tests only: drop the memoised descriptor. */
40
+ export declare function resetDescriptorCache(): void;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The API descriptor: a generated, committed transcription of Google's Discovery
3
+ * documents, pruned to what making a REQUEST needs.
4
+ *
5
+ * Generated at BUILD time by `scripts/generate-descriptor.mjs` and committed, so
6
+ * there is no network dependency at startup and nothing breaks offline. Drift is a
7
+ * CI check, not a production surprise.
8
+ *
9
+ * It records what Discovery says about how to CALL Google. It records nothing
10
+ * about what a RESPONSE means — Discovery's `schemas` block (~90% of the raw
11
+ * document) is deliberately DISCARDED. A descriptor that knows response shapes is
12
+ * a descriptor that can start helpfully reshaping them.
13
+ *
14
+ * See ADR-103.
15
+ */
16
+ import { readFile } from 'node:fs/promises';
17
+ import { dirname, resolve } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ let cached;
20
+ /**
21
+ * Load the descriptor. Resolved as a sibling of this module, which makes it work
22
+ * under `src/` (vitest) and under `build/` (the shipped server) alike — the same
23
+ * trick `loadManifest()` uses, and the reason `npx` works.
24
+ */
25
+ export async function loadDescriptor() {
26
+ if (cached)
27
+ return cached;
28
+ const here = dirname(fileURLToPath(import.meta.url));
29
+ const raw = await readFile(resolve(here, 'descriptor.json'), 'utf-8');
30
+ cached = JSON.parse(raw);
31
+ return cached;
32
+ }
33
+ /** Tests only: drop the memoised descriptor. */
34
+ export function resetDescriptorCache() {
35
+ cached = undefined;
36
+ }
37
+ //# sourceMappingURL=descriptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor.js","sourceRoot":"","sources":["../../src/google/descriptor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAuCzC,IAAI,MAAiC,CAAC;AAEtC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC;IACtE,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;IAC1C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,oBAAoB;IAClC,MAAM,GAAG,SAAS,CAAC;AACrB,CAAC"}