@mcp-z/oauth-google 1.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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/dist/cjs/index.d.cts +16 -0
  4. package/dist/cjs/index.d.ts +16 -0
  5. package/dist/cjs/index.js +112 -0
  6. package/dist/cjs/index.js.map +1 -0
  7. package/dist/cjs/lib/dcr-router.d.cts +44 -0
  8. package/dist/cjs/lib/dcr-router.d.ts +44 -0
  9. package/dist/cjs/lib/dcr-router.js +1189 -0
  10. package/dist/cjs/lib/dcr-router.js.map +1 -0
  11. package/dist/cjs/lib/dcr-utils.d.cts +160 -0
  12. package/dist/cjs/lib/dcr-utils.d.ts +160 -0
  13. package/dist/cjs/lib/dcr-utils.js +860 -0
  14. package/dist/cjs/lib/dcr-utils.js.map +1 -0
  15. package/dist/cjs/lib/dcr-verify.d.cts +53 -0
  16. package/dist/cjs/lib/dcr-verify.d.ts +53 -0
  17. package/dist/cjs/lib/dcr-verify.js +193 -0
  18. package/dist/cjs/lib/dcr-verify.js.map +1 -0
  19. package/dist/cjs/lib/fetch-with-timeout.d.cts +14 -0
  20. package/dist/cjs/lib/fetch-with-timeout.d.ts +14 -0
  21. package/dist/cjs/lib/fetch-with-timeout.js +257 -0
  22. package/dist/cjs/lib/fetch-with-timeout.js.map +1 -0
  23. package/dist/cjs/lib/token-verifier.d.cts +44 -0
  24. package/dist/cjs/lib/token-verifier.d.ts +44 -0
  25. package/dist/cjs/lib/token-verifier.js +253 -0
  26. package/dist/cjs/lib/token-verifier.js.map +1 -0
  27. package/dist/cjs/package.json +1 -0
  28. package/dist/cjs/providers/dcr.d.cts +107 -0
  29. package/dist/cjs/providers/dcr.d.ts +107 -0
  30. package/dist/cjs/providers/dcr.js +584 -0
  31. package/dist/cjs/providers/dcr.js.map +1 -0
  32. package/dist/cjs/providers/loopback-oauth.d.cts +119 -0
  33. package/dist/cjs/providers/loopback-oauth.d.ts +119 -0
  34. package/dist/cjs/providers/loopback-oauth.js +1334 -0
  35. package/dist/cjs/providers/loopback-oauth.js.map +1 -0
  36. package/dist/cjs/providers/service-account.d.cts +131 -0
  37. package/dist/cjs/providers/service-account.d.ts +131 -0
  38. package/dist/cjs/providers/service-account.js +800 -0
  39. package/dist/cjs/providers/service-account.js.map +1 -0
  40. package/dist/cjs/schemas/index.d.cts +20 -0
  41. package/dist/cjs/schemas/index.d.ts +20 -0
  42. package/dist/cjs/schemas/index.js +37 -0
  43. package/dist/cjs/schemas/index.js.map +1 -0
  44. package/dist/cjs/setup/config.d.cts +112 -0
  45. package/dist/cjs/setup/config.d.ts +112 -0
  46. package/dist/cjs/setup/config.js +236 -0
  47. package/dist/cjs/setup/config.js.map +1 -0
  48. package/dist/cjs/types.d.cts +173 -0
  49. package/dist/cjs/types.d.ts +173 -0
  50. package/dist/cjs/types.js +16 -0
  51. package/dist/cjs/types.js.map +1 -0
  52. package/dist/esm/index.d.ts +16 -0
  53. package/dist/esm/index.js +16 -0
  54. package/dist/esm/index.js.map +1 -0
  55. package/dist/esm/lib/dcr-router.d.ts +44 -0
  56. package/dist/esm/lib/dcr-router.js +515 -0
  57. package/dist/esm/lib/dcr-router.js.map +1 -0
  58. package/dist/esm/lib/dcr-utils.d.ts +160 -0
  59. package/dist/esm/lib/dcr-utils.js +270 -0
  60. package/dist/esm/lib/dcr-utils.js.map +1 -0
  61. package/dist/esm/lib/dcr-verify.d.ts +53 -0
  62. package/dist/esm/lib/dcr-verify.js +53 -0
  63. package/dist/esm/lib/dcr-verify.js.map +1 -0
  64. package/dist/esm/lib/fetch-with-timeout.d.ts +14 -0
  65. package/dist/esm/lib/fetch-with-timeout.js +30 -0
  66. package/dist/esm/lib/fetch-with-timeout.js.map +1 -0
  67. package/dist/esm/lib/token-verifier.d.ts +44 -0
  68. package/dist/esm/lib/token-verifier.js +53 -0
  69. package/dist/esm/lib/token-verifier.js.map +1 -0
  70. package/dist/esm/package.json +1 -0
  71. package/dist/esm/providers/dcr.d.ts +107 -0
  72. package/dist/esm/providers/dcr.js +242 -0
  73. package/dist/esm/providers/dcr.js.map +1 -0
  74. package/dist/esm/providers/loopback-oauth.d.ts +119 -0
  75. package/dist/esm/providers/loopback-oauth.js +639 -0
  76. package/dist/esm/providers/loopback-oauth.js.map +1 -0
  77. package/dist/esm/providers/service-account.d.ts +131 -0
  78. package/dist/esm/providers/service-account.js +353 -0
  79. package/dist/esm/providers/service-account.js.map +1 -0
  80. package/dist/esm/schemas/index.d.ts +20 -0
  81. package/dist/esm/schemas/index.js +18 -0
  82. package/dist/esm/schemas/index.js.map +1 -0
  83. package/dist/esm/setup/config.d.ts +112 -0
  84. package/dist/esm/setup/config.js +258 -0
  85. package/dist/esm/setup/config.js.map +1 -0
  86. package/dist/esm/types.d.ts +173 -0
  87. package/dist/esm/types.js +6 -0
  88. package/dist/esm/types.js.map +1 -0
  89. package/package.json +89 -0
@@ -0,0 +1,1334 @@
1
+ /**
2
+ * Loopback OAuth Implementation (RFC 8252)
3
+ *
4
+ * Implements OAuth 2.0 Authorization Code Flow with PKCE using loopback interface redirection.
5
+ * Uses ephemeral local server with OS-assigned port (RFC 8252 Section 8.3).
6
+ */ "use strict";
7
+ Object.defineProperty(exports, "__esModule", {
8
+ value: true
9
+ });
10
+ function _export(target, all) {
11
+ for(var name in all)Object.defineProperty(target, name, {
12
+ enumerable: true,
13
+ get: Object.getOwnPropertyDescriptor(all, name).get
14
+ });
15
+ }
16
+ _export(exports, {
17
+ get LoopbackOAuthProvider () {
18
+ return LoopbackOAuthProvider;
19
+ },
20
+ get createGoogleFileAuth () {
21
+ return createGoogleFileAuth;
22
+ }
23
+ });
24
+ var _oauth = require("@mcp-z/oauth");
25
+ var _googleauthlibrary = require("google-auth-library");
26
+ var _http = /*#__PURE__*/ _interop_require_wildcard(require("http"));
27
+ var _open = /*#__PURE__*/ _interop_require_default(require("open"));
28
+ var _typests = require("../types.js");
29
+ function _array_like_to_array(arr, len) {
30
+ if (len == null || len > arr.length) len = arr.length;
31
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
32
+ return arr2;
33
+ }
34
+ function _array_without_holes(arr) {
35
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
36
+ }
37
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
38
+ try {
39
+ var info = gen[key](arg);
40
+ var value = info.value;
41
+ } catch (error) {
42
+ reject(error);
43
+ return;
44
+ }
45
+ if (info.done) {
46
+ resolve(value);
47
+ } else {
48
+ Promise.resolve(value).then(_next, _throw);
49
+ }
50
+ }
51
+ function _async_to_generator(fn) {
52
+ return function() {
53
+ var self = this, args = arguments;
54
+ return new Promise(function(resolve, reject) {
55
+ var gen = fn.apply(self, args);
56
+ function _next(value) {
57
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
58
+ }
59
+ function _throw(err) {
60
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
61
+ }
62
+ _next(undefined);
63
+ });
64
+ };
65
+ }
66
+ function _class_call_check(instance, Constructor) {
67
+ if (!(instance instanceof Constructor)) {
68
+ throw new TypeError("Cannot call a class as a function");
69
+ }
70
+ }
71
+ function _define_property(obj, key, value) {
72
+ if (key in obj) {
73
+ Object.defineProperty(obj, key, {
74
+ value: value,
75
+ enumerable: true,
76
+ configurable: true,
77
+ writable: true
78
+ });
79
+ } else {
80
+ obj[key] = value;
81
+ }
82
+ return obj;
83
+ }
84
+ function _instanceof(left, right) {
85
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
86
+ return !!right[Symbol.hasInstance](left);
87
+ } else {
88
+ return left instanceof right;
89
+ }
90
+ }
91
+ function _interop_require_default(obj) {
92
+ return obj && obj.__esModule ? obj : {
93
+ default: obj
94
+ };
95
+ }
96
+ function _getRequireWildcardCache(nodeInterop) {
97
+ if (typeof WeakMap !== "function") return null;
98
+ var cacheBabelInterop = new WeakMap();
99
+ var cacheNodeInterop = new WeakMap();
100
+ return (_getRequireWildcardCache = function(nodeInterop) {
101
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
102
+ })(nodeInterop);
103
+ }
104
+ function _interop_require_wildcard(obj, nodeInterop) {
105
+ if (!nodeInterop && obj && obj.__esModule) {
106
+ return obj;
107
+ }
108
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
109
+ return {
110
+ default: obj
111
+ };
112
+ }
113
+ var cache = _getRequireWildcardCache(nodeInterop);
114
+ if (cache && cache.has(obj)) {
115
+ return cache.get(obj);
116
+ }
117
+ var newObj = {
118
+ __proto__: null
119
+ };
120
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
121
+ for(var key in obj){
122
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
123
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
124
+ if (desc && (desc.get || desc.set)) {
125
+ Object.defineProperty(newObj, key, desc);
126
+ } else {
127
+ newObj[key] = obj[key];
128
+ }
129
+ }
130
+ }
131
+ newObj.default = obj;
132
+ if (cache) {
133
+ cache.set(obj, newObj);
134
+ }
135
+ return newObj;
136
+ }
137
+ function _iterable_to_array(iter) {
138
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
139
+ }
140
+ function _non_iterable_spread() {
141
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
142
+ }
143
+ function _object_spread(target) {
144
+ for(var i = 1; i < arguments.length; i++){
145
+ var source = arguments[i] != null ? arguments[i] : {};
146
+ var ownKeys = Object.keys(source);
147
+ if (typeof Object.getOwnPropertySymbols === "function") {
148
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
149
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
150
+ }));
151
+ }
152
+ ownKeys.forEach(function(key) {
153
+ _define_property(target, key, source[key]);
154
+ });
155
+ }
156
+ return target;
157
+ }
158
+ function ownKeys(object, enumerableOnly) {
159
+ var keys = Object.keys(object);
160
+ if (Object.getOwnPropertySymbols) {
161
+ var symbols = Object.getOwnPropertySymbols(object);
162
+ if (enumerableOnly) {
163
+ symbols = symbols.filter(function(sym) {
164
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
165
+ });
166
+ }
167
+ keys.push.apply(keys, symbols);
168
+ }
169
+ return keys;
170
+ }
171
+ function _object_spread_props(target, source) {
172
+ source = source != null ? source : {};
173
+ if (Object.getOwnPropertyDescriptors) {
174
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
175
+ } else {
176
+ ownKeys(Object(source)).forEach(function(key) {
177
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
178
+ });
179
+ }
180
+ return target;
181
+ }
182
+ function _to_consumable_array(arr) {
183
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
184
+ }
185
+ function _unsupported_iterable_to_array(o, minLen) {
186
+ if (!o) return;
187
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
188
+ var n = Object.prototype.toString.call(o).slice(8, -1);
189
+ if (n === "Object" && o.constructor) n = o.constructor.name;
190
+ if (n === "Map" || n === "Set") return Array.from(n);
191
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
192
+ }
193
+ function _ts_generator(thisArg, body) {
194
+ var f, y, t, _ = {
195
+ label: 0,
196
+ sent: function() {
197
+ if (t[0] & 1) throw t[1];
198
+ return t[1];
199
+ },
200
+ trys: [],
201
+ ops: []
202
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
203
+ return d(g, "next", {
204
+ value: verb(0)
205
+ }), d(g, "throw", {
206
+ value: verb(1)
207
+ }), d(g, "return", {
208
+ value: verb(2)
209
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
210
+ value: function() {
211
+ return this;
212
+ }
213
+ }), g;
214
+ function verb(n) {
215
+ return function(v) {
216
+ return step([
217
+ n,
218
+ v
219
+ ]);
220
+ };
221
+ }
222
+ function step(op) {
223
+ if (f) throw new TypeError("Generator is already executing.");
224
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
225
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
226
+ if (y = 0, t) op = [
227
+ op[0] & 2,
228
+ t.value
229
+ ];
230
+ switch(op[0]){
231
+ case 0:
232
+ case 1:
233
+ t = op;
234
+ break;
235
+ case 4:
236
+ _.label++;
237
+ return {
238
+ value: op[1],
239
+ done: false
240
+ };
241
+ case 5:
242
+ _.label++;
243
+ y = op[1];
244
+ op = [
245
+ 0
246
+ ];
247
+ continue;
248
+ case 7:
249
+ op = _.ops.pop();
250
+ _.trys.pop();
251
+ continue;
252
+ default:
253
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
254
+ _ = 0;
255
+ continue;
256
+ }
257
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
258
+ _.label = op[1];
259
+ break;
260
+ }
261
+ if (op[0] === 6 && _.label < t[1]) {
262
+ _.label = t[1];
263
+ t = op;
264
+ break;
265
+ }
266
+ if (t && _.label < t[2]) {
267
+ _.label = t[2];
268
+ _.ops.push(op);
269
+ break;
270
+ }
271
+ if (t[2]) _.ops.pop();
272
+ _.trys.pop();
273
+ continue;
274
+ }
275
+ op = body.call(thisArg, _);
276
+ } catch (e) {
277
+ op = [
278
+ 6,
279
+ e
280
+ ];
281
+ y = 0;
282
+ } finally{
283
+ f = t = 0;
284
+ }
285
+ if (op[0] & 5) throw op[1];
286
+ return {
287
+ value: op[0] ? op[1] : void 0,
288
+ done: true
289
+ };
290
+ }
291
+ }
292
+ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
293
+ "use strict";
294
+ function LoopbackOAuthProvider(config) {
295
+ _class_call_check(this, LoopbackOAuthProvider);
296
+ this.config = config;
297
+ }
298
+ var _proto = LoopbackOAuthProvider.prototype;
299
+ /**
300
+ * Get access token from Keyv using compound key
301
+ *
302
+ * @param accountId - Account identifier (email address). Required for loopback OAuth.
303
+ * @returns Access token for API requests
304
+ */ _proto.getAccessToken = function getAccessToken(accountId) {
305
+ return _async_to_generator(function() {
306
+ var _this_config, logger, service, tokenStore, effectiveAccountId, _tmp, storedToken, refreshedToken, error, headless, _this_config1, clientId, scope, existingAccounts, hasOtherAccounts, authUrl, hint, baseDescriptor, descriptor, _ref, token, email;
307
+ return _ts_generator(this, function(_state) {
308
+ switch(_state.label){
309
+ case 0:
310
+ _this_config = this.config, logger = _this_config.logger, service = _this_config.service, tokenStore = _this_config.tokenStore;
311
+ if (!(accountId !== null && accountId !== void 0)) return [
312
+ 3,
313
+ 1
314
+ ];
315
+ _tmp = accountId;
316
+ return [
317
+ 3,
318
+ 3
319
+ ];
320
+ case 1:
321
+ return [
322
+ 4,
323
+ (0, _oauth.getActiveAccount)(tokenStore, {
324
+ service: service
325
+ })
326
+ ];
327
+ case 2:
328
+ _tmp = _state.sent();
329
+ _state.label = 3;
330
+ case 3:
331
+ effectiveAccountId = _tmp;
332
+ if (!effectiveAccountId) return [
333
+ 3,
334
+ 9
335
+ ];
336
+ logger.debug('Getting access token', {
337
+ service: service,
338
+ accountId: effectiveAccountId
339
+ });
340
+ return [
341
+ 4,
342
+ (0, _oauth.getToken)(tokenStore, {
343
+ accountId: effectiveAccountId,
344
+ service: service
345
+ })
346
+ ];
347
+ case 4:
348
+ storedToken = _state.sent();
349
+ if (storedToken && this.isTokenValid(storedToken)) {
350
+ logger.debug('Using stored access token', {
351
+ accountId: effectiveAccountId
352
+ });
353
+ return [
354
+ 2,
355
+ storedToken.accessToken
356
+ ];
357
+ }
358
+ if (!(storedToken === null || storedToken === void 0 ? void 0 : storedToken.refreshToken)) return [
359
+ 3,
360
+ 9
361
+ ];
362
+ _state.label = 5;
363
+ case 5:
364
+ _state.trys.push([
365
+ 5,
366
+ 8,
367
+ ,
368
+ 9
369
+ ]);
370
+ logger.info('Refreshing expired access token', {
371
+ accountId: effectiveAccountId
372
+ });
373
+ return [
374
+ 4,
375
+ this.refreshAccessToken(storedToken.refreshToken)
376
+ ];
377
+ case 6:
378
+ refreshedToken = _state.sent();
379
+ return [
380
+ 4,
381
+ (0, _oauth.setToken)(tokenStore, {
382
+ accountId: effectiveAccountId,
383
+ service: service
384
+ }, refreshedToken)
385
+ ];
386
+ case 7:
387
+ _state.sent();
388
+ return [
389
+ 2,
390
+ refreshedToken.accessToken
391
+ ];
392
+ case 8:
393
+ error = _state.sent();
394
+ logger.info('Token refresh failed, starting new OAuth flow', {
395
+ accountId: effectiveAccountId,
396
+ error: _instanceof(error, Error) ? error.message : String(error)
397
+ });
398
+ return [
399
+ 3,
400
+ 9
401
+ ];
402
+ case 9:
403
+ // No valid token or no account - check if we can start OAuth flow
404
+ headless = this.config.headless;
405
+ if (!headless) return [
406
+ 3,
407
+ 11
408
+ ];
409
+ // In headless mode (production), cannot start OAuth flow
410
+ // Throw AuthRequiredError with auth_url descriptor for MCP tool response
411
+ _this_config1 = this.config, clientId = _this_config1.clientId, scope = _this_config1.scope;
412
+ return [
413
+ 4,
414
+ this.getExistingAccounts()
415
+ ];
416
+ case 10:
417
+ existingAccounts = _state.sent();
418
+ hasOtherAccounts = effectiveAccountId ? existingAccounts.length > 0 && !existingAccounts.includes(effectiveAccountId) : existingAccounts.length > 0;
419
+ // Build informational OAuth URL for headless mode
420
+ // Note: No redirect_uri included - user must use account-add tool which starts proper ephemeral server
421
+ authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
422
+ authUrl.searchParams.set('client_id', clientId);
423
+ authUrl.searchParams.set('response_type', 'code');
424
+ authUrl.searchParams.set('scope', scope);
425
+ authUrl.searchParams.set('access_type', 'offline');
426
+ authUrl.searchParams.set('prompt', 'consent');
427
+ if (hasOtherAccounts) {
428
+ hint = "Existing ".concat(service, " accounts found. Use account-list to view, account-switch to change account, or account-add to add new account");
429
+ } else if (effectiveAccountId) {
430
+ hint = "Use account-add to authenticate ".concat(effectiveAccountId);
431
+ } else {
432
+ hint = 'Use account-add to authenticate interactively';
433
+ }
434
+ baseDescriptor = {
435
+ kind: 'auth_url',
436
+ provider: 'google',
437
+ url: authUrl.toString(),
438
+ hint: hint
439
+ };
440
+ descriptor = effectiveAccountId ? _object_spread_props(_object_spread({}, baseDescriptor), {
441
+ accountId: effectiveAccountId
442
+ }) : baseDescriptor;
443
+ throw new _typests.AuthRequiredError(descriptor);
444
+ case 11:
445
+ // Interactive mode - start ephemeral OAuth flow
446
+ logger.info('Starting ephemeral OAuth flow', {
447
+ service: service,
448
+ headless: headless
449
+ });
450
+ return [
451
+ 4,
452
+ this.performEphemeralOAuthFlow()
453
+ ];
454
+ case 12:
455
+ _ref = _state.sent(), token = _ref.token, email = _ref.email;
456
+ // Store token with email as accountId
457
+ return [
458
+ 4,
459
+ (0, _oauth.setToken)(tokenStore, {
460
+ accountId: email,
461
+ service: service
462
+ }, token)
463
+ ];
464
+ case 13:
465
+ _state.sent();
466
+ // Register account in account management system
467
+ return [
468
+ 4,
469
+ (0, _oauth.addAccount)(tokenStore, {
470
+ service: service,
471
+ accountId: email
472
+ })
473
+ ];
474
+ case 14:
475
+ _state.sent();
476
+ // Set as active account so subsequent getAccessToken() calls find it
477
+ return [
478
+ 4,
479
+ (0, _oauth.setActiveAccount)(tokenStore, {
480
+ service: service,
481
+ accountId: email
482
+ })
483
+ ];
484
+ case 15:
485
+ _state.sent();
486
+ // Store account metadata (email, added timestamp)
487
+ return [
488
+ 4,
489
+ (0, _oauth.setAccountInfo)(tokenStore, {
490
+ service: service,
491
+ accountId: email
492
+ }, {
493
+ email: email,
494
+ addedAt: new Date().toISOString()
495
+ })
496
+ ];
497
+ case 16:
498
+ _state.sent();
499
+ logger.info('OAuth flow completed', {
500
+ service: service,
501
+ accountId: email
502
+ });
503
+ return [
504
+ 2,
505
+ token.accessToken
506
+ ];
507
+ }
508
+ });
509
+ }).call(this);
510
+ };
511
+ /**
512
+ * Convert to googleapis-compatible OAuth2Client
513
+ *
514
+ * @param accountId - Account identifier for multi-account support (e.g., 'user@example.com')
515
+ * @returns OAuth2Client configured for the specified account
516
+ */ _proto.toAuth = function toAuth(accountId) {
517
+ var _this = this;
518
+ var _this_config = this.config, clientId = _this_config.clientId, clientSecret = _this_config.clientSecret;
519
+ var client = new _googleauthlibrary.OAuth2Client(_object_spread({
520
+ clientId: clientId
521
+ }, clientSecret && {
522
+ clientSecret: clientSecret
523
+ }));
524
+ // @ts-expect-error - Override protected method to inject fresh token
525
+ client.getRequestMetadataAsync = function(_url) {
526
+ return _async_to_generator(function() {
527
+ var token, headers;
528
+ return _ts_generator(this, function(_state) {
529
+ switch(_state.label){
530
+ case 0:
531
+ return [
532
+ 4,
533
+ this.getAccessToken(accountId)
534
+ ];
535
+ case 1:
536
+ token = _state.sent();
537
+ // Update client credentials for googleapis compatibility
538
+ client.credentials = {
539
+ access_token: token,
540
+ token_type: 'Bearer'
541
+ };
542
+ // Return headers as Map (required by authclient.js addUserProjectAndAuthHeaders)
543
+ headers = new Map();
544
+ headers.set('authorization', "Bearer ".concat(token));
545
+ return [
546
+ 2,
547
+ {
548
+ headers: headers
549
+ }
550
+ ];
551
+ }
552
+ });
553
+ }).call(_this);
554
+ };
555
+ return client;
556
+ };
557
+ /**
558
+ * Authenticate new account with OAuth flow
559
+ * Triggers account selection, stores token, registers account
560
+ *
561
+ * @returns Email address of newly authenticated account
562
+ * @throws Error in headless mode (cannot open browser for OAuth)
563
+ */ _proto.authenticateNewAccount = function authenticateNewAccount() {
564
+ return _async_to_generator(function() {
565
+ var _this_config, logger, headless, service, tokenStore, _ref, token, email;
566
+ return _ts_generator(this, function(_state) {
567
+ switch(_state.label){
568
+ case 0:
569
+ _this_config = this.config, logger = _this_config.logger, headless = _this_config.headless, service = _this_config.service, tokenStore = _this_config.tokenStore;
570
+ if (headless) {
571
+ throw new Error('Cannot authenticate new account in headless mode - interactive OAuth required');
572
+ }
573
+ logger.info('Starting new account authentication', {
574
+ service: service
575
+ });
576
+ return [
577
+ 4,
578
+ this.performEphemeralOAuthFlow()
579
+ ];
580
+ case 1:
581
+ _ref = _state.sent(), token = _ref.token, email = _ref.email;
582
+ // Store token
583
+ return [
584
+ 4,
585
+ (0, _oauth.setToken)(tokenStore, {
586
+ accountId: email,
587
+ service: service
588
+ }, token)
589
+ ];
590
+ case 2:
591
+ _state.sent();
592
+ // Register account
593
+ return [
594
+ 4,
595
+ (0, _oauth.addAccount)(tokenStore, {
596
+ service: service,
597
+ accountId: email
598
+ })
599
+ ];
600
+ case 3:
601
+ _state.sent();
602
+ // Set as active account
603
+ return [
604
+ 4,
605
+ (0, _oauth.setActiveAccount)(tokenStore, {
606
+ service: service,
607
+ accountId: email
608
+ })
609
+ ];
610
+ case 4:
611
+ _state.sent();
612
+ // Store account metadata
613
+ return [
614
+ 4,
615
+ (0, _oauth.setAccountInfo)(tokenStore, {
616
+ service: service,
617
+ accountId: email
618
+ }, {
619
+ email: email,
620
+ addedAt: new Date().toISOString()
621
+ })
622
+ ];
623
+ case 5:
624
+ _state.sent();
625
+ logger.info('New account authenticated', {
626
+ service: service,
627
+ email: email
628
+ });
629
+ return [
630
+ 2,
631
+ email
632
+ ];
633
+ }
634
+ });
635
+ }).call(this);
636
+ };
637
+ /**
638
+ * Get user email from Google's userinfo endpoint (pure query)
639
+ * Used to query email for existing authenticated account
640
+ *
641
+ * @param accountId - Account identifier to get email for
642
+ * @returns User's email address
643
+ */ _proto.getUserEmail = function getUserEmail(accountId) {
644
+ return _async_to_generator(function() {
645
+ var token, response, _, _1, _2, userInfo;
646
+ return _ts_generator(this, function(_state) {
647
+ switch(_state.label){
648
+ case 0:
649
+ return [
650
+ 4,
651
+ this.getAccessToken(accountId)
652
+ ];
653
+ case 1:
654
+ token = _state.sent();
655
+ return [
656
+ 4,
657
+ fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
658
+ headers: {
659
+ Authorization: "Bearer ".concat(token)
660
+ }
661
+ })
662
+ ];
663
+ case 2:
664
+ response = _state.sent();
665
+ if (!!response.ok) return [
666
+ 3,
667
+ 4
668
+ ];
669
+ _ = Error.bind;
670
+ _2 = (_1 = "Failed to get user info: ".concat(response.status, " ")).concat;
671
+ return [
672
+ 4,
673
+ response.text()
674
+ ];
675
+ case 3:
676
+ throw new (_.apply(Error, [
677
+ void 0,
678
+ _2.apply(_1, [
679
+ _state.sent()
680
+ ])
681
+ ]));
682
+ case 4:
683
+ return [
684
+ 4,
685
+ response.json()
686
+ ];
687
+ case 5:
688
+ userInfo = _state.sent();
689
+ return [
690
+ 2,
691
+ userInfo.email
692
+ ];
693
+ }
694
+ });
695
+ }).call(this);
696
+ };
697
+ /**
698
+ * Check for existing accounts in token storage (incremental OAuth detection)
699
+ *
700
+ * Uses key-utils helper for forward compatibility with key format changes.
701
+ *
702
+ * @returns Array of account IDs that have tokens for this service
703
+ */ _proto.getExistingAccounts = function getExistingAccounts() {
704
+ return _async_to_generator(function() {
705
+ var _this_config, service, tokenStore;
706
+ return _ts_generator(this, function(_state) {
707
+ _this_config = this.config, service = _this_config.service, tokenStore = _this_config.tokenStore;
708
+ return [
709
+ 2,
710
+ (0, _oauth.listAccountIds)(tokenStore, service)
711
+ ];
712
+ });
713
+ }).call(this);
714
+ };
715
+ _proto.isTokenValid = function isTokenValid(token) {
716
+ if (!token.expiresAt) return true; // No expiry = assume valid
717
+ return Date.now() < token.expiresAt - 60000; // 1 minute buffer
718
+ };
719
+ /**
720
+ * Fetch user email from Google OAuth2 userinfo endpoint
721
+ * Called during OAuth flow to get email for accountId
722
+ *
723
+ * @param accessToken - Fresh access token from OAuth exchange
724
+ * @returns User's email address
725
+ */ _proto.fetchUserEmailFromToken = function fetchUserEmailFromToken(accessToken) {
726
+ return _async_to_generator(function() {
727
+ var logger, response, errorText, userInfo, email;
728
+ return _ts_generator(this, function(_state) {
729
+ switch(_state.label){
730
+ case 0:
731
+ logger = this.config.logger;
732
+ return [
733
+ 4,
734
+ fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
735
+ headers: {
736
+ Authorization: "Bearer ".concat(accessToken)
737
+ }
738
+ })
739
+ ];
740
+ case 1:
741
+ response = _state.sent();
742
+ if (!!response.ok) return [
743
+ 3,
744
+ 3
745
+ ];
746
+ return [
747
+ 4,
748
+ response.text()
749
+ ];
750
+ case 2:
751
+ errorText = _state.sent();
752
+ throw new Error("Failed to fetch user email: HTTP ".concat(response.status, " - ").concat(errorText));
753
+ case 3:
754
+ return [
755
+ 4,
756
+ response.json()
757
+ ];
758
+ case 4:
759
+ userInfo = _state.sent();
760
+ email = userInfo.email;
761
+ logger.debug('Fetched user email from Google userinfo API', {
762
+ email: email
763
+ });
764
+ return [
765
+ 2,
766
+ email
767
+ ];
768
+ }
769
+ });
770
+ }).call(this);
771
+ };
772
+ _proto.performEphemeralOAuthFlow = function performEphemeralOAuthFlow() {
773
+ return _async_to_generator(function() {
774
+ var _this, _this_config, clientId, scope, headless, logger, configRedirectUri, targetHost, targetPort, targetProtocol, callbackPath, useConfiguredUri, parsed;
775
+ return _ts_generator(this, function(_state) {
776
+ _this = this;
777
+ _this_config = this.config, clientId = _this_config.clientId, scope = _this_config.scope, headless = _this_config.headless, logger = _this_config.logger, configRedirectUri = _this_config.redirectUri;
778
+ // Parse redirectUri if provided to extract host, protocol, port, and path
779
+ targetHost = 'localhost'; // Default: localhost (match registered redirect URI)
780
+ targetPort = 0; // Default: OS-assigned ephemeral port
781
+ targetProtocol = 'http:'; // Default: http
782
+ callbackPath = '/callback'; // Default callback path
783
+ useConfiguredUri = false;
784
+ if (configRedirectUri) {
785
+ try {
786
+ parsed = new URL(configRedirectUri);
787
+ // Use configured redirect URI as-is for production deployments
788
+ targetHost = parsed.hostname;
789
+ targetProtocol = parsed.protocol;
790
+ // Extract port from URL (use default ports if not specified)
791
+ if (parsed.port) {
792
+ targetPort = Number.parseInt(parsed.port, 10);
793
+ } else {
794
+ targetPort = parsed.protocol === 'https:' ? 443 : 80;
795
+ }
796
+ // Extract path (default to /callback if URL has no path or just '/')
797
+ if (parsed.pathname && parsed.pathname !== '/') {
798
+ callbackPath = parsed.pathname;
799
+ }
800
+ useConfiguredUri = true;
801
+ logger.debug('Using configured redirect URI', {
802
+ host: targetHost,
803
+ protocol: targetProtocol,
804
+ port: targetPort,
805
+ path: callbackPath,
806
+ redirectUri: configRedirectUri
807
+ });
808
+ } catch (error) {
809
+ logger.warn('Failed to parse redirectUri, using ephemeral defaults', {
810
+ redirectUri: configRedirectUri,
811
+ error: _instanceof(error, Error) ? error.message : String(error)
812
+ });
813
+ // Continue with defaults (127.0.0.1, port 0, http, /callback)
814
+ }
815
+ }
816
+ return [
817
+ 2,
818
+ new Promise(function(resolve, reject) {
819
+ // Generate PKCE challenge
820
+ var _generatePKCE = (0, _oauth.generatePKCE)(), codeVerifier = _generatePKCE.verifier, codeChallenge = _generatePKCE.challenge;
821
+ var server = null;
822
+ var serverPort;
823
+ var finalRedirectUri; // Will be set in server.listen callback
824
+ // Create ephemeral server with OS-assigned port (RFC 8252)
825
+ server = _http.createServer(function(req, res) {
826
+ return _async_to_generator(function() {
827
+ var url, code, _$error, tokenResponse, cachedToken, email, exchangeError;
828
+ return _ts_generator(this, function(_state) {
829
+ switch(_state.label){
830
+ case 0:
831
+ if (!req.url) {
832
+ res.writeHead(400, {
833
+ 'Content-Type': 'text/html'
834
+ });
835
+ res.end((0, _oauth.getErrorTemplate)('Invalid request'));
836
+ server === null || server === void 0 ? void 0 : server.close();
837
+ reject(new Error('Invalid request: missing URL'));
838
+ return [
839
+ 2
840
+ ];
841
+ }
842
+ url = new URL(req.url, "http://127.0.0.1:".concat(serverPort));
843
+ if (!(url.pathname === callbackPath)) return [
844
+ 3,
845
+ 6
846
+ ];
847
+ code = url.searchParams.get('code');
848
+ _$error = url.searchParams.get('error');
849
+ if (_$error) {
850
+ res.writeHead(400, {
851
+ 'Content-Type': 'text/html'
852
+ });
853
+ res.end((0, _oauth.getErrorTemplate)(_$error));
854
+ server === null || server === void 0 ? void 0 : server.close();
855
+ reject(new Error("OAuth error: ".concat(_$error)));
856
+ return [
857
+ 2
858
+ ];
859
+ }
860
+ if (!code) {
861
+ res.writeHead(400, {
862
+ 'Content-Type': 'text/html'
863
+ });
864
+ res.end((0, _oauth.getErrorTemplate)('No authorization code received'));
865
+ server === null || server === void 0 ? void 0 : server.close();
866
+ reject(new Error('No authorization code received'));
867
+ return [
868
+ 2
869
+ ];
870
+ }
871
+ _state.label = 1;
872
+ case 1:
873
+ _state.trys.push([
874
+ 1,
875
+ 4,
876
+ ,
877
+ 5
878
+ ]);
879
+ return [
880
+ 4,
881
+ this.exchangeCodeForToken(code, codeVerifier, finalRedirectUri)
882
+ ];
883
+ case 2:
884
+ tokenResponse = _state.sent();
885
+ // Build cached token
886
+ cachedToken = _object_spread({
887
+ accessToken: tokenResponse.access_token
888
+ }, tokenResponse.refresh_token !== undefined && {
889
+ refreshToken: tokenResponse.refresh_token
890
+ }, tokenResponse.expires_in !== undefined && {
891
+ expiresAt: Date.now() + tokenResponse.expires_in * 1000
892
+ }, tokenResponse.scope !== undefined && {
893
+ scope: tokenResponse.scope
894
+ });
895
+ return [
896
+ 4,
897
+ this.fetchUserEmailFromToken(tokenResponse.access_token)
898
+ ];
899
+ case 3:
900
+ email = _state.sent();
901
+ res.writeHead(200, {
902
+ 'Content-Type': 'text/html'
903
+ });
904
+ res.end((0, _oauth.getSuccessTemplate)());
905
+ server === null || server === void 0 ? void 0 : server.close();
906
+ resolve({
907
+ token: cachedToken,
908
+ email: email
909
+ });
910
+ return [
911
+ 3,
912
+ 5
913
+ ];
914
+ case 4:
915
+ exchangeError = _state.sent();
916
+ logger.error('Token exchange failed', {
917
+ error: _instanceof(exchangeError, Error) ? exchangeError.message : String(exchangeError)
918
+ });
919
+ res.writeHead(500, {
920
+ 'Content-Type': 'text/html'
921
+ });
922
+ res.end((0, _oauth.getErrorTemplate)('Token exchange failed'));
923
+ server === null || server === void 0 ? void 0 : server.close();
924
+ reject(exchangeError);
925
+ return [
926
+ 3,
927
+ 5
928
+ ];
929
+ case 5:
930
+ return [
931
+ 3,
932
+ 7
933
+ ];
934
+ case 6:
935
+ res.writeHead(404, {
936
+ 'Content-Type': 'text/plain'
937
+ });
938
+ res.end('Not Found');
939
+ _state.label = 7;
940
+ case 7:
941
+ return [
942
+ 2
943
+ ];
944
+ }
945
+ });
946
+ }).call(_this);
947
+ });
948
+ // Listen on targetPort (0 for OS assignment, or custom port from redirectUri)
949
+ server.listen(targetPort, targetHost, function() {
950
+ var address = server === null || server === void 0 ? void 0 : server.address();
951
+ if (!address || typeof address === 'string') {
952
+ server === null || server === void 0 ? void 0 : server.close();
953
+ reject(new Error('Failed to start ephemeral server'));
954
+ return;
955
+ }
956
+ serverPort = address.port;
957
+ // Construct final redirect URI
958
+ if (useConfiguredUri && configRedirectUri) {
959
+ // Use configured redirect URI as-is for production
960
+ finalRedirectUri = configRedirectUri;
961
+ } else {
962
+ // Construct ephemeral redirect URI with actual server port
963
+ finalRedirectUri = "".concat(targetProtocol, "//").concat(targetHost, ":").concat(serverPort).concat(callbackPath);
964
+ }
965
+ // Build auth URL
966
+ var authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
967
+ authUrl.searchParams.set('client_id', clientId);
968
+ authUrl.searchParams.set('redirect_uri', finalRedirectUri);
969
+ authUrl.searchParams.set('response_type', 'code');
970
+ authUrl.searchParams.set('scope', scope);
971
+ authUrl.searchParams.set('access_type', 'offline');
972
+ authUrl.searchParams.set('prompt', 'consent');
973
+ authUrl.searchParams.set('code_challenge', codeChallenge);
974
+ authUrl.searchParams.set('code_challenge_method', 'S256');
975
+ logger.info('Ephemeral OAuth server started', {
976
+ port: serverPort,
977
+ headless: headless
978
+ });
979
+ if (headless) {
980
+ // Headless mode: Print auth URL to stderr (stdout is MCP protocol)
981
+ console.error('\n🔐 OAuth Authorization Required');
982
+ console.error('📋 Please visit this URL in your browser:\n');
983
+ console.error(" ".concat(authUrl.toString(), "\n"));
984
+ console.error('⏳ Waiting for authorization...\n');
985
+ } else {
986
+ // Interactive mode: Open browser automatically
987
+ logger.info('Opening browser for OAuth authorization');
988
+ (0, _open.default)(authUrl.toString()).catch(function(error) {
989
+ logger.info('Failed to open browser automatically', {
990
+ error: error.message
991
+ });
992
+ console.error('\n🔐 OAuth Authorization Required');
993
+ console.error(" ".concat(authUrl.toString(), "\n"));
994
+ });
995
+ }
996
+ });
997
+ // Timeout after 5 minutes
998
+ setTimeout(function() {
999
+ if (server) {
1000
+ server.close();
1001
+ reject(new Error('OAuth flow timed out after 5 minutes'));
1002
+ }
1003
+ }, 5 * 60 * 1000);
1004
+ })
1005
+ ];
1006
+ });
1007
+ }).call(this);
1008
+ };
1009
+ _proto.exchangeCodeForToken = function exchangeCodeForToken(code, codeVerifier, redirectUri) {
1010
+ return _async_to_generator(function() {
1011
+ var _this_config, clientId, clientSecret, tokenUrl, params, body, response, errorText;
1012
+ return _ts_generator(this, function(_state) {
1013
+ switch(_state.label){
1014
+ case 0:
1015
+ _this_config = this.config, clientId = _this_config.clientId, clientSecret = _this_config.clientSecret;
1016
+ tokenUrl = 'https://oauth2.googleapis.com/token';
1017
+ params = {
1018
+ code: code,
1019
+ client_id: clientId,
1020
+ redirect_uri: redirectUri,
1021
+ grant_type: 'authorization_code',
1022
+ code_verifier: codeVerifier
1023
+ };
1024
+ if (clientSecret) {
1025
+ params.client_secret = clientSecret;
1026
+ }
1027
+ body = new URLSearchParams(params);
1028
+ return [
1029
+ 4,
1030
+ fetch(tokenUrl, {
1031
+ method: 'POST',
1032
+ headers: {
1033
+ 'Content-Type': 'application/x-www-form-urlencoded'
1034
+ },
1035
+ body: body.toString()
1036
+ })
1037
+ ];
1038
+ case 1:
1039
+ response = _state.sent();
1040
+ if (!!response.ok) return [
1041
+ 3,
1042
+ 3
1043
+ ];
1044
+ return [
1045
+ 4,
1046
+ response.text()
1047
+ ];
1048
+ case 2:
1049
+ errorText = _state.sent();
1050
+ throw new Error("Token exchange failed: ".concat(response.status, " ").concat(errorText));
1051
+ case 3:
1052
+ return [
1053
+ 4,
1054
+ response.json()
1055
+ ];
1056
+ case 4:
1057
+ return [
1058
+ 2,
1059
+ _state.sent()
1060
+ ];
1061
+ }
1062
+ });
1063
+ }).call(this);
1064
+ };
1065
+ _proto.refreshAccessToken = function refreshAccessToken(refreshToken) {
1066
+ return _async_to_generator(function() {
1067
+ var _this_config, clientId, clientSecret, tokenUrl, params, body, response, errorText, tokenResponse;
1068
+ return _ts_generator(this, function(_state) {
1069
+ switch(_state.label){
1070
+ case 0:
1071
+ _this_config = this.config, clientId = _this_config.clientId, clientSecret = _this_config.clientSecret;
1072
+ tokenUrl = 'https://oauth2.googleapis.com/token';
1073
+ params = {
1074
+ refresh_token: refreshToken,
1075
+ client_id: clientId,
1076
+ grant_type: 'refresh_token'
1077
+ };
1078
+ if (clientSecret) {
1079
+ params.client_secret = clientSecret;
1080
+ }
1081
+ body = new URLSearchParams(params);
1082
+ return [
1083
+ 4,
1084
+ fetch(tokenUrl, {
1085
+ method: 'POST',
1086
+ headers: {
1087
+ 'Content-Type': 'application/x-www-form-urlencoded'
1088
+ },
1089
+ body: body.toString()
1090
+ })
1091
+ ];
1092
+ case 1:
1093
+ response = _state.sent();
1094
+ if (!!response.ok) return [
1095
+ 3,
1096
+ 3
1097
+ ];
1098
+ return [
1099
+ 4,
1100
+ response.text()
1101
+ ];
1102
+ case 2:
1103
+ errorText = _state.sent();
1104
+ throw new Error("Token refresh failed: ".concat(response.status, " ").concat(errorText));
1105
+ case 3:
1106
+ return [
1107
+ 4,
1108
+ response.json()
1109
+ ];
1110
+ case 4:
1111
+ tokenResponse = _state.sent();
1112
+ return [
1113
+ 2,
1114
+ _object_spread({
1115
+ accessToken: tokenResponse.access_token,
1116
+ refreshToken: refreshToken
1117
+ }, tokenResponse.expires_in !== undefined && {
1118
+ expiresAt: Date.now() + tokenResponse.expires_in * 1000
1119
+ }, tokenResponse.scope !== undefined && {
1120
+ scope: tokenResponse.scope
1121
+ })
1122
+ ];
1123
+ }
1124
+ });
1125
+ }).call(this);
1126
+ };
1127
+ /**
1128
+ * Create authentication middleware for MCP tools, resources, and prompts
1129
+ *
1130
+ * Returns position-aware middleware wrappers that enrich handlers with authentication context.
1131
+ * The middleware handles token retrieval, refresh, and AuthRequiredError automatically.
1132
+ *
1133
+ * Single-user middleware for desktop/CLI apps where ONE user runs the entire process:
1134
+ * - Desktop applications (Claude Desktop)
1135
+ * - CLI tools (Gmail CLI)
1136
+ * - Personal automation scripts
1137
+ *
1138
+ * All requests use token lookups based on the active account or account override.
1139
+ *
1140
+ * @returns Object with withToolAuth, withResourceAuth, withPromptAuth methods
1141
+ *
1142
+ * @example
1143
+ * ```typescript
1144
+ * const loopback = new LoopbackOAuthProvider({ service: 'gmail', ... });
1145
+ * const authMiddleware = loopback.authMiddleware();
1146
+ * const tools = toolFactories.map(f => f()).map(authMiddleware.withToolAuth);
1147
+ * const resources = resourceFactories.map(f => f()).map(authMiddleware.withResourceAuth);
1148
+ * const prompts = promptFactories.map(f => f()).map(authMiddleware.withPromptAuth);
1149
+ * ```
1150
+ */ _proto.authMiddleware = function authMiddleware() {
1151
+ var _this = this;
1152
+ var _this_config = this.config, service = _this_config.service, tokenStore = _this_config.tokenStore, logger = _this_config.logger;
1153
+ // Shared wrapper logic - extracts extra parameter from specified position
1154
+ // Generic T captures the actual module type; handler is cast from unknown to callable
1155
+ var wrapAtPosition = function(module, extraPosition) {
1156
+ var _this1 = _this;
1157
+ var operation = module.name;
1158
+ var originalHandler = module.handler;
1159
+ var wrappedHandler = function() {
1160
+ for(var _len = arguments.length, allArgs = new Array(_len), _key = 0; _key < _len; _key++){
1161
+ allArgs[_key] = arguments[_key];
1162
+ }
1163
+ return _async_to_generator(function() {
1164
+ var extra, accountId, _ref, _extra__meta, _tmp, error, effectiveAccountId, _tmp1, auth, error1, authRequiredResponse;
1165
+ return _ts_generator(this, function(_state) {
1166
+ switch(_state.label){
1167
+ case 0:
1168
+ // Extract extra from the correct position
1169
+ extra = allArgs[extraPosition];
1170
+ _state.label = 1;
1171
+ case 1:
1172
+ _state.trys.push([
1173
+ 1,
1174
+ 13,
1175
+ ,
1176
+ 14
1177
+ ]);
1178
+ _state.label = 2;
1179
+ case 2:
1180
+ _state.trys.push([
1181
+ 2,
1182
+ 6,
1183
+ ,
1184
+ 7
1185
+ ]);
1186
+ if (!((_ref = (_extra__meta = extra._meta) === null || _extra__meta === void 0 ? void 0 : _extra__meta.accountId) !== null && _ref !== void 0)) return [
1187
+ 3,
1188
+ 3
1189
+ ];
1190
+ _tmp = _ref;
1191
+ return [
1192
+ 3,
1193
+ 5
1194
+ ];
1195
+ case 3:
1196
+ return [
1197
+ 4,
1198
+ (0, _oauth.getActiveAccount)(tokenStore, {
1199
+ service: service
1200
+ })
1201
+ ];
1202
+ case 4:
1203
+ _tmp = _state.sent();
1204
+ _state.label = 5;
1205
+ case 5:
1206
+ accountId = _tmp;
1207
+ return [
1208
+ 3,
1209
+ 7
1210
+ ];
1211
+ case 6:
1212
+ error = _state.sent();
1213
+ if (_instanceof(error, Error) && (error.code === 'REQUIRES_AUTHENTICATION' || error.name === 'AccountManagerError')) {
1214
+ accountId = undefined;
1215
+ } else {
1216
+ throw error;
1217
+ }
1218
+ return [
1219
+ 3,
1220
+ 7
1221
+ ];
1222
+ case 7:
1223
+ // Eagerly validate token exists or trigger OAuth flow
1224
+ return [
1225
+ 4,
1226
+ this.getAccessToken(accountId)
1227
+ ];
1228
+ case 8:
1229
+ _state.sent();
1230
+ if (!(accountId !== null && accountId !== void 0)) return [
1231
+ 3,
1232
+ 9
1233
+ ];
1234
+ _tmp1 = accountId;
1235
+ return [
1236
+ 3,
1237
+ 11
1238
+ ];
1239
+ case 9:
1240
+ return [
1241
+ 4,
1242
+ (0, _oauth.getActiveAccount)(tokenStore, {
1243
+ service: service
1244
+ })
1245
+ ];
1246
+ case 10:
1247
+ _tmp1 = _state.sent();
1248
+ _state.label = 11;
1249
+ case 11:
1250
+ effectiveAccountId = _tmp1;
1251
+ if (!effectiveAccountId) {
1252
+ throw new Error("No account found after OAuth flow for service ".concat(service));
1253
+ }
1254
+ auth = this.toAuth(effectiveAccountId);
1255
+ // Inject authContext and logger into extra
1256
+ extra.authContext = {
1257
+ auth: auth,
1258
+ accountId: effectiveAccountId
1259
+ };
1260
+ extra.logger = logger;
1261
+ return [
1262
+ 4,
1263
+ originalHandler.apply(void 0, _to_consumable_array(allArgs))
1264
+ ];
1265
+ case 12:
1266
+ // Call original handler with all args
1267
+ return [
1268
+ 2,
1269
+ _state.sent()
1270
+ ];
1271
+ case 13:
1272
+ error1 = _state.sent();
1273
+ if (_instanceof(error1, _typests.AuthRequiredError)) {
1274
+ logger.info('Authentication required', {
1275
+ service: service,
1276
+ tool: operation,
1277
+ descriptor: error1.descriptor
1278
+ });
1279
+ // Return auth_required response wrapped in { result } to match tool outputSchema pattern
1280
+ // Tools define outputSchema: z.object({ result: discriminatedUnion(...) }) where auth_required is a branch
1281
+ authRequiredResponse = {
1282
+ type: 'auth_required',
1283
+ provider: service,
1284
+ message: "Authentication required for ".concat(operation, ". Please authenticate with ").concat(service, "."),
1285
+ url: error1.descriptor.kind === 'auth_url' ? error1.descriptor.url : undefined
1286
+ };
1287
+ return [
1288
+ 2,
1289
+ {
1290
+ content: [
1291
+ {
1292
+ type: 'text',
1293
+ text: JSON.stringify({
1294
+ result: authRequiredResponse
1295
+ })
1296
+ }
1297
+ ],
1298
+ structuredContent: {
1299
+ result: authRequiredResponse
1300
+ }
1301
+ }
1302
+ ];
1303
+ }
1304
+ throw error1;
1305
+ case 14:
1306
+ return [
1307
+ 2
1308
+ ];
1309
+ }
1310
+ });
1311
+ }).call(_this1);
1312
+ };
1313
+ return _object_spread_props(_object_spread({}, module), {
1314
+ handler: wrappedHandler
1315
+ });
1316
+ };
1317
+ return {
1318
+ withToolAuth: function(module) {
1319
+ return wrapAtPosition(module, 1);
1320
+ },
1321
+ withResourceAuth: function(module) {
1322
+ return wrapAtPosition(module, 2);
1323
+ },
1324
+ withPromptAuth: function(module) {
1325
+ return wrapAtPosition(module, 0);
1326
+ }
1327
+ };
1328
+ };
1329
+ return LoopbackOAuthProvider;
1330
+ }();
1331
+ function createGoogleFileAuth(config) {
1332
+ return new LoopbackOAuthProvider(config);
1333
+ }
1334
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }