@mcpher/gas-fakes 2.3.14 → 2.3.16

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 (58) hide show
  1. package/README.md +11 -5
  2. package/gf_agent/README.md +101 -0
  3. package/gf_agent/SKILL.md +397 -0
  4. package/gf_agent/documentation.md +105 -0
  5. package/gf_agent/gf-agent-contributor/SKILL.md +56 -0
  6. package/gf_agent/index.md +21 -0
  7. package/gf_agent/knowledge/00-execution-context.md +4 -0
  8. package/gf_agent/knowledge/01-drive.md +12 -0
  9. package/gf_agent/knowledge/02-syntax.md +13 -0
  10. package/gf_agent/knowledge/03-auth.md +15 -0
  11. package/gf_agent/knowledge/04-advanced.md +24 -0
  12. package/gf_agent/knowledge/05-sheets-forms.md +25 -0
  13. package/gf_agent/knowledge/06-jdbc-cloudsql.md +21 -0
  14. package/gf_agent/knowledge/07-jdbc-auth-details.md +30 -0
  15. package/gf_agent/knowledge/08-docs-limitations.md +4 -0
  16. package/gf_agent/knowledge/09-orchestrator-pattern.md +54 -0
  17. package/gf_agent/knowledge/10-sandbox-security.md +62 -0
  18. package/gf_agent/knowledge/11-chart-builder-limitations.md +15 -0
  19. package/gf_agent/knowledge/12-gmail-eventual-consistency.md +13 -0
  20. package/gf_agent/knowledge/README.md +16 -0
  21. package/gf_agent/scripts/SKILL.template.md +65 -0
  22. package/gf_agent/skills/base.md +156 -0
  23. package/gf_agent/skills/cache.md +20 -0
  24. package/gf_agent/skills/calendar.md +780 -0
  25. package/gf_agent/skills/charts.md +127 -0
  26. package/gf_agent/skills/document.md +6752 -0
  27. package/gf_agent/skills/drive.md +423 -0
  28. package/gf_agent/skills/forms.md +4036 -0
  29. package/gf_agent/skills/gmail.md +576 -0
  30. package/gf_agent/skills/jdbc.md +3101 -0
  31. package/gf_agent/skills/lock.md +20 -0
  32. package/gf_agent/skills/properties.md +19 -0
  33. package/gf_agent/skills/script.md +50 -0
  34. package/gf_agent/skills/slides.md +5054 -0
  35. package/gf_agent/skills/spreadsheet.md +56075 -0
  36. package/gf_agent/skills/urlfetch.md +28 -0
  37. package/gf_agent/skills/utilities.md +33 -0
  38. package/gf_agent/skills/xml.md +270 -0
  39. package/package.json +1 -1
  40. package/src/cli/mcp.js +82 -67
  41. package/src/services/advgmail/fakeadvgmailmessages.js +85 -3
  42. package/src/services/documentapp/fakecontainerelement.js +88 -0
  43. package/src/services/driveapp/fakedrivemeta.js +1 -1
  44. package/src/services/gmailapp/fakegmailapp.js +217 -1
  45. package/src/services/gmailapp/fakegmailattachment.js +5 -0
  46. package/src/services/gmailapp/fakegmaildraft.js +32 -4
  47. package/src/services/gmailapp/fakegmaillabel.js +45 -0
  48. package/src/services/gmailapp/fakegmailmessage.js +212 -9
  49. package/src/services/gmailapp/fakegmailthread.js +151 -1
  50. package/src/services/slidesapp/fakecolorscheme.js +29 -10
  51. package/src/services/slidesapp/fakepresentation.js +0 -8
  52. package/src/services/spreadsheetapp/fakeembeddedchartbuilder.js +113 -28
  53. package/src/services/spreadsheetapp/fakespreadsheetapp.js +15 -1
  54. package/src/support/sxgmail.js +22 -2
  55. package/src/support/sxjdbc.js +16 -3
  56. package/src/support/utils.js +2 -2
  57. package/docs_discovery.json +0 -4939
  58. package/drive_tools.js +0 -20
@@ -167,7 +167,7 @@ class FakeGmailThread {
167
167
  }
168
168
 
169
169
  Gmail.Users.Threads.modify({ addLabelIds: [label.getId()] }, 'me', this.getId());
170
- return this;
170
+ return this.refresh();
171
171
  }
172
172
 
173
173
  removeLabel(label) {
@@ -215,6 +215,156 @@ class FakeGmailThread {
215
215
  }
216
216
  }
217
217
  Gmail.Users.Threads.modify({ removeLabelIds: [label.getId()] }, 'me', this.getId());
218
+ return this.refresh();
219
+ }
220
+
221
+ __hasLabel(label) {
222
+ if (!this.__threadResource.messages) return false;
223
+ for (const m of this.__threadResource.messages) {
224
+ if (m.labelIds && m.labelIds.includes(label)) return true;
225
+ }
226
+ return false;
227
+ }
228
+
229
+ hasStarredMessages() {
230
+ ScriptApp.__behavior.checkMethod('GmailThread', 'hasStarredMessages');
231
+ return this.__hasLabel('STARRED');
232
+ }
233
+
234
+ isImportant() {
235
+ ScriptApp.__behavior.checkMethod('GmailThread', 'isImportant');
236
+ return this.__hasLabel('IMPORTANT');
237
+ }
238
+
239
+ isInChats() {
240
+ ScriptApp.__behavior.checkMethod('GmailThread', 'isInChats');
241
+ return this.__hasLabel('CHAT');
242
+ }
243
+
244
+ isInInbox() {
245
+ ScriptApp.__behavior.checkMethod('GmailThread', 'isInInbox');
246
+ return this.__hasLabel('INBOX');
247
+ }
248
+
249
+ isInPriorityInbox() {
250
+ ScriptApp.__behavior.checkMethod('GmailThread', 'isInPriorityInbox');
251
+ return this.__hasLabel('INBOX') && this.__hasLabel('IMPORTANT');
252
+ }
253
+
254
+ isInSpam() {
255
+ ScriptApp.__behavior.checkMethod('GmailThread', 'isInSpam');
256
+ return this.__hasLabel('SPAM');
257
+ }
258
+
259
+ isInTrash() {
260
+ ScriptApp.__behavior.checkMethod('GmailThread', 'isInTrash');
261
+ return this.__hasLabel('TRASH');
262
+ }
263
+
264
+ isUnread() {
265
+ ScriptApp.__behavior.checkMethod('GmailThread', 'isUnread');
266
+ return this.__hasLabel('UNREAD');
267
+ }
268
+
269
+ getFirstMessageSubject() {
270
+ ScriptApp.__behavior.checkMethod('GmailThread', 'getFirstMessageSubject');
271
+ const msgs = this.getMessages();
272
+ return msgs.length > 0 ? msgs[0].getSubject() : '';
273
+ }
274
+
275
+ getLastMessageDate() {
276
+ ScriptApp.__behavior.checkMethod('GmailThread', 'getLastMessageDate');
277
+ const msgs = this.getMessages();
278
+ return msgs.length > 0 ? msgs[msgs.length - 1].getDate() : new Date();
279
+ }
280
+
281
+ getMessageCount() {
282
+ ScriptApp.__behavior.checkMethod('GmailThread', 'getMessageCount');
283
+ return this.getMessages().length;
284
+ }
285
+
286
+ getPermalink() {
287
+ ScriptApp.__behavior.checkMethod('GmailThread', 'getPermalink');
288
+ return `https://mail.google.com/mail/u/0/#inbox/${this.getId()}`;
289
+ }
290
+
291
+ refresh() {
292
+ ScriptApp.__behavior.checkMethod('GmailThread', 'refresh');
293
+ this.__threadResource = Gmail.Users.Threads.get('me', this.getId());
294
+ return this;
295
+ }
296
+
297
+ markImportant() {
298
+ ScriptApp.__behavior.checkMethod('GmailThread', 'markImportant');
299
+ Gmail.Users.Threads.modify({ addLabelIds: ['IMPORTANT'] }, 'me', this.getId());
300
+ return this.refresh();
301
+ }
302
+
303
+ markRead() {
304
+ ScriptApp.__behavior.checkMethod('GmailThread', 'markRead');
305
+ Gmail.Users.Threads.modify({ removeLabelIds: ['UNREAD'] }, 'me', this.getId());
306
+ return this.refresh();
307
+ }
308
+
309
+ markUnimportant() {
310
+ ScriptApp.__behavior.checkMethod('GmailThread', 'markUnimportant');
311
+ Gmail.Users.Threads.modify({ removeLabelIds: ['IMPORTANT'] }, 'me', this.getId());
312
+ return this.refresh();
313
+ }
314
+
315
+ markUnread() {
316
+ ScriptApp.__behavior.checkMethod('GmailThread', 'markUnread');
317
+ Gmail.Users.Threads.modify({ addLabelIds: ['UNREAD'] }, 'me', this.getId());
318
+ return this.refresh();
319
+ }
320
+
321
+ moveToArchive() {
322
+ ScriptApp.__behavior.checkMethod('GmailThread', 'moveToArchive');
323
+ Gmail.Users.Threads.modify({ removeLabelIds: ['INBOX'] }, 'me', this.getId());
324
+ return this.refresh();
325
+ }
326
+
327
+ moveToInbox() {
328
+ ScriptApp.__behavior.checkMethod('GmailThread', 'moveToInbox');
329
+ Gmail.Users.Threads.modify({ addLabelIds: ['INBOX'] }, 'me', this.getId());
330
+ return this.refresh();
331
+ }
332
+
333
+ moveToSpam() {
334
+ ScriptApp.__behavior.checkMethod('GmailThread', 'moveToSpam');
335
+ Gmail.Users.Threads.modify({ addLabelIds: ['SPAM'] }, 'me', this.getId());
336
+ return this.refresh();
337
+ }
338
+
339
+ moveToTrash() {
340
+ ScriptApp.__behavior.checkMethod('GmailThread', 'moveToTrash');
341
+ Gmail.Users.Threads.trash('me', this.getId());
342
+ return this.refresh();
343
+ }
344
+
345
+ createDraftReply(body, options) {
346
+ ScriptApp.__behavior.checkMethod('GmailThread', 'createDraftReply');
347
+ const msgs = this.getMessages();
348
+ return msgs.length > 0 ? msgs[msgs.length - 1].createDraftReply(body, options) : null;
349
+ }
350
+
351
+ createDraftReplyAll(body, options) {
352
+ ScriptApp.__behavior.checkMethod('GmailThread', 'createDraftReplyAll');
353
+ const msgs = this.getMessages();
354
+ return msgs.length > 0 ? msgs[msgs.length - 1].createDraftReplyAll(body, options) : null;
355
+ }
356
+
357
+ reply(body, options) {
358
+ ScriptApp.__behavior.checkMethod('GmailThread', 'reply');
359
+ const msgs = this.getMessages();
360
+ if (msgs.length > 0) msgs[msgs.length - 1].reply(body, options);
361
+ return this;
362
+ }
363
+
364
+ replyAll(body, options) {
365
+ ScriptApp.__behavior.checkMethod('GmailThread', 'replyAll');
366
+ const msgs = this.getMessages();
367
+ if (msgs.length > 0) msgs[msgs.length - 1].replyAll(body, options);
218
368
  return this;
219
369
  }
220
370
 
@@ -81,9 +81,9 @@ export class FakeColorScheme {
81
81
  * @param {FakeColor} color
82
82
  * @returns {FakeColorScheme} self
83
83
  */
84
- setConcreteColor(themeColorType, color) {
84
+ setConcreteColor(themeColorType, ...colorArgs) {
85
85
  const { nargs, matchThrow } = signatureArgs(arguments, "ColorScheme.setConcreteColor");
86
- if (nargs !== 2) matchThrow();
86
+ if (nargs < 2 || nargs > 4) matchThrow();
87
87
 
88
88
  const master = this.__masterPage;
89
89
  if (!master) throw new Error('Could not find master page for color scheme');
@@ -96,15 +96,34 @@ export class FakeColorScheme {
96
96
  const currentResource = this.__resource;
97
97
  const colors = [...(currentResource.colors || [])];
98
98
 
99
- // Convert the new Color to API format
100
99
  const apiColor = {};
101
- if (color.getColorType().toString() === 'RGB') {
102
- const rgb = color.asRgbColor();
103
- apiColor.red = rgb.getRed() / 255;
104
- apiColor.green = rgb.getGreen() / 255;
105
- apiColor.blue = rgb.getBlue() / 255;
106
- } else if (color.getColorType().toString() === 'THEME') {
107
- apiColor.themeColor = color.asThemeColor().getThemeColorType().toString();
100
+ if (colorArgs.length === 3) {
101
+ // (ThemeColorType, r, g, b)
102
+ apiColor.red = colorArgs[0] / 255;
103
+ apiColor.green = colorArgs[1] / 255;
104
+ apiColor.blue = colorArgs[2] / 255;
105
+ } else if (typeof colorArgs[0] === 'string') {
106
+ // (ThemeColorType, hexString)
107
+ const hex = colorArgs[0];
108
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
109
+ if (result) {
110
+ apiColor.red = parseInt(result[1], 16) / 255;
111
+ apiColor.green = parseInt(result[2], 16) / 255;
112
+ apiColor.blue = parseInt(result[3], 16) / 255;
113
+ } else {
114
+ throw new Error("Invalid hex color string");
115
+ }
116
+ } else {
117
+ // (ThemeColorType, Color)
118
+ const color = colorArgs[0];
119
+ if (color.getColorType().toString() === 'RGB') {
120
+ const rgb = color.asRgbColor();
121
+ apiColor.red = rgb.getRed() / 255;
122
+ apiColor.green = rgb.getGreen() / 255;
123
+ apiColor.blue = rgb.getBlue() / 255;
124
+ } else if (color.getColorType().toString() === 'THEME') {
125
+ apiColor.themeColor = color.asThemeColor().getThemeColorType().toString();
126
+ }
108
127
  }
109
128
 
110
129
  // Find and update or add the color pair
@@ -52,14 +52,6 @@ export class FakePresentation {
52
52
  return `https://docs.google.com/presentation/d/${this.getId()}/edit`;
53
53
  }
54
54
 
55
- /**
56
- * Gets the color scheme of the presentation.
57
- * @returns {FakeColorScheme} The color scheme.
58
- */
59
- getColorScheme() {
60
- return newFakeColorScheme(this);
61
- }
62
-
63
55
  /**
64
56
  * Gets the masters in the presentation.
65
57
  * @returns {FakeMaster[]} The masters.
@@ -1,5 +1,5 @@
1
1
  import { Proxies } from "../../support/proxies.js";
2
- import { signatureArgs } from "../../support/helpers.js";
2
+ import { signatureArgs, notYetImplemented } from "../../support/helpers.js";
3
3
  import { Utils } from "../../support/utils.js";
4
4
  import { makeSheetsGridRange } from "./sheetrangehelpers.js";
5
5
  import { newFakeEmbeddedChart } from "./fakeembeddedchart.js";
@@ -155,6 +155,25 @@ export class FakeEmbeddedChartBuilder {
155
155
  }
156
156
  }
157
157
 
158
+ // Apply colors to series
159
+ if (this.__colors && basic && basic.series) {
160
+ basic.series.forEach((s, i) => {
161
+ if (this.__colors[i]) {
162
+ const hex = this.__colors[i];
163
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
164
+ if (result) {
165
+ s.colorStyle = {
166
+ rgbColor: {
167
+ red: parseInt(result[1], 16) / 255,
168
+ green: parseInt(result[2], 16) / 255,
169
+ blue: parseInt(result[3], 16) / 255
170
+ }
171
+ };
172
+ }
173
+ }
174
+ });
175
+ }
176
+
158
177
  // 2. Handle Specialized Spec Blocks
159
178
  if (basic && basic.chartType === "PIE") {
160
179
  spec.pieChart = {
@@ -233,43 +252,109 @@ export class FakeEmbeddedChartBuilder {
233
252
  setTransposeRowsAndColumns(transpose) { return this; }
234
253
 
235
254
  // --- Chart Specific Builder Methods ---
236
- reverseCategories() { return this; }
255
+ __getAxis(position) {
256
+ if (!this.__apiChart.spec.basicChart) {
257
+ this.__apiChart.spec.basicChart = { axis: [], domains: [], series: [] };
258
+ }
259
+ if (!this.__apiChart.spec.basicChart.axis) {
260
+ this.__apiChart.spec.basicChart.axis = [];
261
+ }
262
+ let axis = this.__apiChart.spec.basicChart.axis.find(a => a.position === position);
263
+ if (!axis) {
264
+ axis = { position };
265
+ this.__apiChart.spec.basicChart.axis.push(axis);
266
+ }
267
+ return axis;
268
+ }
269
+
270
+ reverseCategories() { notYetImplemented('reverseCategories'); return this; }
237
271
  setBackgroundColor(color) { return this.setOption("backgroundColor", color); }
238
- setColors(colors) { return this; }
272
+
273
+ setColors(colors) {
274
+ ScriptApp.__behavior.checkMethod("EmbeddedChartBuilder", "setColors");
275
+ this.__colors = Array.isArray(colors) ? colors : [colors];
276
+ return this;
277
+ }
278
+
239
279
  setLegendPosition(position) {
240
280
  this.__apiChart.spec.basicChart.legendPosition = position ? position.toString() : "RIGHT_LEGEND";
241
281
  return this;
242
282
  }
243
- setLegendTextStyle(textStyle) { return this; }
244
- setPointStyle(pointStyle) { return this; }
245
- setRange(min, max) { return this; }
246
- setStacked() { return this; }
283
+
284
+ setLegendTextStyle(textStyle) { notYetImplemented('setLegendTextStyle'); return this; }
285
+ setPointStyle(pointStyle) { notYetImplemented('setPointStyle'); return this; }
286
+
287
+ setRange(min, max) {
288
+ ScriptApp.__behavior.checkMethod("EmbeddedChartBuilder", "setRange");
289
+ const chartType = this.__apiChart.spec.basicChart ? this.__apiChart.spec.basicChart.chartType : null;
290
+ if (chartType === "BAR") {
291
+ return this.setXAxisRange(min, max);
292
+ }
293
+ return this.setYAxisRange(min, max);
294
+ }
295
+
296
+ setStacked() {
297
+ ScriptApp.__behavior.checkMethod("EmbeddedChartBuilder", "setStacked");
298
+ if (this.__apiChart.spec.basicChart) {
299
+ this.__apiChart.spec.basicChart.stackedType = "STACKED";
300
+ }
301
+ return this;
302
+ }
303
+
247
304
  setTitle(title) {
305
+ ScriptApp.__behavior.checkMethod("EmbeddedChartBuilder", "setTitle");
248
306
  this.__apiChart.spec.title = title;
249
307
  return this;
250
308
  }
251
- setTitleTextStyle(textStyle) { return this; }
252
- setXAxisTextStyle(textStyle) { return this; }
253
- setXAxisTitle(title) { return this; }
254
- setXAxisTitleTextStyle(textStyle) { return this; }
255
- setYAxisTextStyle(textStyle) { return this; }
256
- setYAxisTitle(title) { return this; }
257
- setYAxisTitleTextStyle(textStyle) { return this; }
258
- useLogScale() { return this; }
309
+
310
+ setTitleTextStyle(textStyle) { notYetImplemented('setTitleTextStyle'); return this; }
311
+ setXAxisTextStyle(textStyle) { notYetImplemented('setXAxisTextStyle'); return this; }
312
+
313
+ setXAxisTitle(title) {
314
+ ScriptApp.__behavior.checkMethod("EmbeddedChartBuilder", "setXAxisTitle");
315
+ this.__getAxis("BOTTOM_AXIS").title = title;
316
+ return this;
317
+ }
318
+
319
+ setXAxisTitleTextStyle(textStyle) { notYetImplemented('setXAxisTitleTextStyle'); return this; }
320
+ setYAxisTextStyle(textStyle) { notYetImplemented('setYAxisTextStyle'); return this; }
321
+
322
+ setYAxisTitle(title) {
323
+ ScriptApp.__behavior.checkMethod("EmbeddedChartBuilder", "setYAxisTitle");
324
+ this.__getAxis("LEFT_AXIS").title = title;
325
+ return this;
326
+ }
327
+
328
+ setYAxisTitleTextStyle(textStyle) { notYetImplemented('setYAxisTitleTextStyle'); return this; }
329
+ useLogScale() { notYetImplemented('useLogScale'); return this; }
259
330
  set3D() { return this.setOption("is3D", true); }
260
- enablePaging(enable, pageSize) { return this; }
261
- enableRtlTable(enable) { return this; }
262
- enableSorting(enable) { return this; }
263
- setFirstRowNumber(number) { return this; }
264
- setInitialSortingAscending(column) { return this; }
265
- setInitialSortingDescending(column) { return this; }
266
- showRowNumberColumn(show) { return this; }
267
- useAlternatingRowStyle(use) { return this; }
268
- setXAxisLogScale() { return this; }
269
- setXAxisRange(min, max) { return this; }
270
- setYAxisLogScale() { return this; }
271
- setYAxisRange(min, max) { return this; }
272
- reverseDirection() { return this; }
331
+ enablePaging(enable, pageSize) { notYetImplemented('enablePaging'); return this; }
332
+ enableRtlTable(enable) { notYetImplemented('enableRtlTable'); return this; }
333
+ enableSorting(enable) { notYetImplemented('enableSorting'); return this; }
334
+ setFirstRowNumber(number) { notYetImplemented('setFirstRowNumber'); return this; }
335
+ setInitialSortingAscending(column) { notYetImplemented('setInitialSortingAscending'); return this; }
336
+ setInitialSortingDescending(column) { notYetImplemented('setInitialSortingDescending'); return this; }
337
+ showRowNumberColumn(show) { notYetImplemented('showRowNumberColumn'); return this; }
338
+ useAlternatingRowStyle(use) { notYetImplemented('useAlternatingRowStyle'); return this; }
339
+ setXAxisLogScale() { notYetImplemented('setXAxisLogScale'); return this; }
340
+
341
+ setXAxisRange(min, max) {
342
+ ScriptApp.__behavior.checkMethod("EmbeddedChartBuilder", "setXAxisRange");
343
+ const axis = this.__getAxis("BOTTOM_AXIS");
344
+ axis.viewWindowOptions = { viewWindowMin: min, viewWindowMax: max };
345
+ return this;
346
+ }
347
+
348
+ setYAxisLogScale() { notYetImplemented('setYAxisLogScale'); return this; }
349
+
350
+ setYAxisRange(min, max) {
351
+ ScriptApp.__behavior.checkMethod("EmbeddedChartBuilder", "setYAxisRange");
352
+ const axis = this.__getAxis("LEFT_AXIS");
353
+ axis.viewWindowOptions = { viewWindowMin: min, viewWindowMax: max };
354
+ return this;
355
+ }
356
+
357
+ reverseDirection() { notYetImplemented('reverseDirection'); return this; }
273
358
 
274
359
  toString() {
275
360
  const type = this.__apiChart.spec.basicChart?.chartType;
@@ -91,7 +91,6 @@ export class FakeSpreadsheetApp {
91
91
  "setActiveRange",
92
92
  "setActiveRangeList",
93
93
  "getUi",
94
- "open",
95
94
 
96
95
  "ChartAggregationType",
97
96
  "ChartTransformationType",
@@ -106,6 +105,21 @@ export class FakeSpreadsheetApp {
106
105
  toString() {
107
106
  return "SpreadsheetApp";
108
107
  }
108
+
109
+ /**
110
+ * Opens the spreadsheet that corresponds to the given File object.
111
+ * @param {File} file A Drive file object representing a spreadsheet.
112
+ * @returns {FakeSpreadsheet} the spreadsheet
113
+ */
114
+ open(file) {
115
+ const { nargs, matchThrow } = signatureArgs(arguments, "SpreadsheetApp.open");
116
+ if (nargs !== 1) matchThrow();
117
+ if (!file || typeof file.getId !== 'function') {
118
+ throw new Error('Invalid file object');
119
+ }
120
+ return this.openById(file.getId());
121
+ }
122
+
109
123
  getActiveSpreadsheet() {
110
124
  if (this.__activeSpreadsheet) return this.__activeSpreadsheet;
111
125
  // because this is a faked container bound app, we need to get the documentId from the config file
@@ -16,8 +16,28 @@ export const sxGmail = async (Auth, { subProp, prop, method, params, options })
16
16
  const tag = `sxGmail for ${methodName}`;
17
17
 
18
18
  return sxRetry(Auth, tag, async () => {
19
- const callish = subProp ? apiClient[prop][subProp] : apiClient[prop];
20
- return callish[method](params, options);
19
+ let context = subProp ? apiClient[prop][subProp] : apiClient[prop];
20
+ let methodFunc = context[method];
21
+
22
+ if (!methodFunc && method.includes('.')) {
23
+ const parts = method.split('.');
24
+ for (const part of parts) {
25
+ if (!context[part]) {
26
+ methodFunc = undefined;
27
+ break;
28
+ }
29
+ methodFunc = context[part];
30
+ if (part !== parts[parts.length - 1]) {
31
+ context = methodFunc;
32
+ }
33
+ }
34
+ }
35
+
36
+ if (typeof methodFunc !== 'function') {
37
+ throw new Error(`Method ${methodName} not found on Gmail API client`);
38
+ }
39
+
40
+ return methodFunc.call(context, params, options);
21
41
  }, {
22
42
  skipLog: (error, response) => {
23
43
  // Don't log 404, 409, or 400 as an error.
@@ -50,11 +50,24 @@ export const sxJdbcConnect = async (Auth, { url, user, password }) => {
50
50
  ssl: disableSsl ? false : { rejectUnauthorized: false }
51
51
  };
52
52
 
53
- if (user !== null && typeof user !== 'undefined' && password !== null && typeof password !== 'undefined') {
53
+ let finalUser = user;
54
+ let finalPassword = password;
55
+
56
+ if ((user === null || typeof user === 'undefined') && (password === null || typeof password === 'undefined')) {
57
+ try {
58
+ const parsedUrl = new URL(pgConnectionString);
59
+ if (parsedUrl.username) finalUser = decodeURIComponent(parsedUrl.username);
60
+ if (parsedUrl.password) finalPassword = decodeURIComponent(parsedUrl.password);
61
+ } catch (e) {
62
+ // ignore parsing errors
63
+ }
64
+ }
65
+
66
+ if (finalUser !== null && typeof finalUser !== 'undefined' && finalPassword !== null && typeof finalPassword !== 'undefined') {
54
67
  client = new pg.Client({
55
68
  ...clientConfig,
56
- user: String(user),
57
- password: String(password)
69
+ user: String(finalUser),
70
+ password: String(finalPassword)
58
71
  });
59
72
  } else {
60
73
  client = new pg.Client(clientConfig);
@@ -363,11 +363,11 @@ const normalizeColorStringToHex = (color) => {
363
363
  if (!is.string(color)) return null;
364
364
  const lowerColor = color.toLowerCase().replace(/\s/g, '');
365
365
  if (colorNameToHex[lowerColor]) {
366
- return colorNameToHex[lowerColor];
366
+ return colorNameToHex[lowerColor].toUpperCase();
367
367
  }
368
368
  // Check if it's a valid hex string
369
369
  if (/^#[0-9a-f]{6}$/i.test(lowerColor)) {
370
- return lowerColor;
370
+ return lowerColor.toUpperCase();
371
371
  }
372
372
  return null; // Invalid color string
373
373
  };