@mcpher/gas-fakes 1.2.31 → 2.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 (53) hide show
  1. package/.gcloudignore +24 -0
  2. package/README.md +5 -5
  3. package/appsscript.json +101 -0
  4. package/exgcp.sh +4 -4
  5. package/package.json +5 -6
  6. package/src/cli/app.js +9 -1
  7. package/src/cli/executor.js +32 -2
  8. package/src/cli/lib-manager.js +0 -1
  9. package/src/cli/setup.js +330 -228
  10. package/src/cli/utils.js +1 -1
  11. package/src/services/advcalendar/clapis.js +4 -2
  12. package/src/services/advdocs/docapis.js +4 -3
  13. package/src/services/advdrive/drapis.js +8 -5
  14. package/src/services/advforms/formsapis.js +4 -3
  15. package/src/services/advgmail/gmailapis.js +4 -3
  16. package/src/services/advsheets/shapis.js +5 -10
  17. package/src/services/advslides/slapis.js +4 -3
  18. package/src/services/driveapp/fakedriveapp.js +10 -2
  19. package/src/services/logger/fakelogger.js +6 -3
  20. package/src/services/scriptapp/app.js +16 -12
  21. package/src/services/scriptapp/behavior.js +132 -107
  22. package/src/services/session/fakesession.js +24 -9
  23. package/src/services/slidesapp/fakepresentation.js +19 -8
  24. package/src/services/slidesapp/fakeslide.js +45 -20
  25. package/src/services/spreadsheetapp/fakesheet.js +9 -7
  26. package/src/services/stores/fakestores.js +20 -18
  27. package/src/services/stores/gasflex.js +13 -14
  28. package/src/services/urlfetchapp/app.js +3 -3
  29. package/src/support/auth.js +227 -55
  30. package/src/support/slogger.js +42 -0
  31. package/src/support/sxauth.js +42 -39
  32. package/src/support/sxcalendar.js +9 -43
  33. package/src/support/sxdocs.js +6 -42
  34. package/src/support/sxdrive.js +32 -73
  35. package/src/support/sxfetch.js +36 -30
  36. package/src/support/sxforms.js +9 -40
  37. package/src/support/sxgmail.js +9 -37
  38. package/src/support/sxretry.js +79 -0
  39. package/src/support/sxsheets.js +6 -37
  40. package/src/support/sxslides.js +5 -36
  41. package/src/support/sxtoken.js +15 -0
  42. package/src/support/syncit.js +27 -10
  43. package/src/support/utils.js +13 -1
  44. package/src/support/workersync/sxfunctions.js +2 -0
  45. package/src/support/workersync/synclogger.js +22 -5
  46. package/src/support/workersync/worker.js +8 -11
  47. package/testlib.sh +1 -1
  48. package/README.RU.md +0 -373
  49. package/env.setup.template +0 -16
  50. package/run.js +0 -35
  51. package/setup.js +0 -689
  52. package/src/Code.js +0 -3
  53. package/src/appsscript.json +0 -5
@@ -7,80 +7,35 @@
7
7
  */
8
8
 
9
9
  import { responseSyncify } from './auth.js';
10
+ import { sxRetry } from './sxretry.js';
10
11
  import intoStream from 'into-stream';
11
12
  import { getStreamAsBuffer } from 'get-stream';
12
13
  import { syncWarn, syncError, syncLog } from './workersync/synclogger.js';
13
14
  import { getDriveApiClient } from '../services/advdrive/drapis.js';
14
-
15
-
16
- /**
17
- * serializable reponse from a sync call
18
- * @typedef SxResponse
19
- * @property {number} status
20
- * @property {string} statusText
21
- * @property {string} responseUrl
22
- * @property {boolean} fromCache
23
- */
24
-
25
- /**
26
- * what's eventually returned from the sync call
27
- * @typedef SxResult
28
- * @property {*} data the data from the api call
29
- * @property {SxResponse} reponse the response from the api call
30
- */
31
-
32
- /**
33
- * serialized blob
34
- * @typedef SerializedBlob
35
- * @property {string} name
36
- * @property {byte[]} bytes
37
- */
38
-
39
-
40
- const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
15
+ import { translateFieldsToV2 } from './utils.js';
41
16
 
42
17
  export const sxDrive = async (Auth, { prop, method, params, options }) => {
43
18
 
44
19
  const apiClient = getDriveApiClient();
45
- //syncLog(JSON.stringify ({ prop, method, params, options }))
46
- const maxRetries = 7;
47
- let delay = 1777;
48
-
49
- for (let i = 0; i < maxRetries; i++) {
50
- let response;
51
- let error;
52
-
53
- try {
54
- const callish = apiClient[prop];
55
- response = await callish[method](params, options);
56
- } catch (err) {
57
- error = err;
58
- response = err.response;
20
+ const tag = `sxDrive for ${prop}.${method}`;
21
+
22
+ return sxRetry(Auth, tag, async () => {
23
+ return apiClient[prop][method](params, options);
24
+ }, {
25
+ extraRetryCheck: (error, response) => {
26
+ // handle invalid field selection - sometimes old files dont support createdTime or modifiedTime
27
+ // we'll try to fallback to createdDate and modifiedDate
28
+ const isInvalidField = error?.message?.includes("Invalid field selection") && (params?.fields?.includes("createdTime") || params?.fields?.includes("modifiedTime"));
29
+
30
+ if (isInvalidField) {
31
+ const fileId = params?.fileId ? ` for file ${params.fileId}` : "";
32
+ syncWarn(`Invalid field selection error on Drive API call ${prop}.${method}${fileId}. Retrying with v2 field names...`);
33
+ params.fields = translateFieldsToV2(params.fields);
34
+ return true;
35
+ }
36
+ return false;
59
37
  }
60
-
61
- const isRetryable = [429, 500, 503].includes(response?.status) || error?.code == 429;
62
-
63
- if (isRetryable && i < maxRetries - 1) {
64
- // add a random jitter to avoid thundering herd
65
- const jitter = Math.floor(Math.random() * 1000);
66
- syncWarn(`Retryable error on Drive API call ${prop}.${method} (status: ${response?.status}). Retrying in ${delay + jitter}ms...`);
67
- await sleep(delay + jitter);
68
- delay *= 2;
69
- continue;
70
- }
71
-
72
- if (error || isRetryable) {
73
- syncError(`Failed in sxDrive for ${prop}.${method}`, error);
74
- return {
75
- data: null,
76
- response: responseSyncify(response)
77
- };
78
- }
79
- return {
80
- data: response.data,
81
- response: responseSyncify(response)
82
- };
83
- }
38
+ });
84
39
  };
85
40
 
86
41
  /**
@@ -173,10 +128,12 @@ const sxStreamer = async ({
173
128
  */
174
129
  export const sxDriveExport = async (_, { id: fileId, mimeType }) => {
175
130
 
176
- return sxStreamer({ params: {
177
- fileId,
178
- mimeType
179
- }, method: 'export' })
131
+ return sxStreamer({
132
+ params: {
133
+ fileId,
134
+ mimeType
135
+ }, method: 'export'
136
+ })
180
137
 
181
138
  }
182
139
  /**
@@ -187,10 +144,12 @@ export const sxDriveExport = async (_, { id: fileId, mimeType }) => {
187
144
  */
188
145
  export const sxDriveMedia = async (_, { id: fileId }) => {
189
146
 
190
- return sxStreamer({params: {
191
- fileId,
192
- alt: 'media'
193
- }, method: 'get' })
147
+ return sxStreamer({
148
+ params: {
149
+ fileId,
150
+ alt: 'media'
151
+ }, method: 'get'
152
+ })
194
153
 
195
154
  }
196
155
 
@@ -1,9 +1,4 @@
1
- /**
2
- * all these functions run in the worker
3
- * thus turning async operations into sync
4
- * note
5
- * - arguments and returns must be serializable ie. primitives or plain objects
6
- */
1
+ import { sxRetry } from './sxretry.js';
7
2
  import got from 'got';
8
3
 
9
4
 
@@ -42,34 +37,45 @@ const fixOptions = (options) => {
42
37
  * @returns {object} an http type response
43
38
  */
44
39
  export const sxFetch = async (Auth, url, options, responseFields) => {
45
- // we need special headers if we're calling google apis
46
- options = Auth.googify(options)
47
40
 
48
- // Always fetch as a buffer to prevent corruption of binary data like images.
49
- // The caller (UrlFetchApp/HttpResponse) will be responsible for decoding to text if needed.
50
- const fixedOptions = fixOptions(options)
41
+ const tag = `sxFetch for ${url}`;
51
42
 
52
- const response = await got(url, {
53
- ...fixedOptions,
54
- responseType: 'buffer'
55
- })
43
+ return sxRetry(Auth, tag, async () => {
44
+ // we need special headers if we're calling google apis
45
+ // notably, the token might be refreshed on retry, so googify must be inside
46
+ const googOptions = Auth.googify(options)
56
47
 
57
- // we cant return the response from this as it cant be serialized
58
- // so we;ll extract oout the fields required
59
- const result = responseFields.reduce((p, c) => {
60
- p[c] = response[c]
61
- return p
62
- }, {})
48
+ // Always fetch as a buffer to prevent corruption of binary data like images.
49
+ // The caller (UrlFetchApp/HttpResponse) will be responsible for decoding to text if needed.
50
+ const fixedOptions = fixOptions(googOptions)
63
51
 
64
- // The rawBody is a Buffer. Convert it to a byte array for proper serialization across the worker boundary.
65
- if (result.rawBody) {
66
- result.rawBody = Array.from(result.rawBody);
67
- }
68
- // The body will also be a buffer
69
- if (result.body && Buffer.isBuffer(result.body)) {
70
- result.body = Array.from(result.body);
71
- }
72
- return result;
52
+ const response = await got(url, {
53
+ ...fixedOptions,
54
+ responseType: 'buffer'
55
+ })
56
+
57
+ // we cant return the response from this as it cant be serialized
58
+ // so we;ll extract oout the fields required
59
+ const result = responseFields.reduce((p, c) => {
60
+ p[c] = response[c]
61
+ return p
62
+ }, {})
63
+
64
+ // The rawBody is a Buffer. Convert it to a byte array for proper serialization across the worker boundary.
65
+ if (result.rawBody) {
66
+ result.rawBody = Array.from(result.rawBody);
67
+ }
68
+ // The body will also be a buffer
69
+ if (result.body && Buffer.isBuffer(result.body)) {
70
+ result.body = Array.from(result.body);
71
+ }
72
+ // we return what sxRetry expects: an object with data and response (or just the object if it's the result)
73
+ // Actually sxRetry expects the result of the func to have .data and .response or it will use the result itself.
74
+ // sxFetch returns the result fields directly in the GAS implementation.
75
+ // Let's wrap it for sxRetry
76
+ return { data: result, response };
77
+
78
+ });
73
79
  }
74
80
 
75
81
  /**
@@ -6,51 +6,20 @@
6
6
  * - arguments and returns must be serializable ie. primitives or plain objects
7
7
  */
8
8
 
9
- import { responseSyncify } from './auth.js';
10
- import { syncWarn, syncError, syncLog } from './workersync/synclogger.js';
9
+ import { sxRetry } from './sxretry.js';
11
10
  import { getFormsApiClient } from '../services/advforms/formsapis.js';
12
11
 
13
- const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
14
-
15
12
  export const sxForms = async (Auth, { prop, subProp, method, params, options = {} }) => {
16
13
 
17
14
  const apiClient = getFormsApiClient();
15
+ const tag = `sxForms for ${prop}${subProp ? '.' + subProp : ''}.${method}`;
18
16
 
19
- const maxRetries = 7;
20
- let delay = 1777;
21
- // syncLog(`Forms API Call: ${prop}${subProp ? '.' + subProp : ''}.${method}, Params: ${JSON.stringify(params)}`);
22
- for (let i = 0; i < maxRetries; i++) {
23
- let response;
24
- let error;
25
-
26
- try {
27
- // Access the base property (e.g., 'forms'), then the sub-property if it exists (e.g., 'responses').
28
- let callish = apiClient[prop];
29
- if (subProp) {
30
- callish = callish[subProp];
31
- }
32
- response = await callish[method](params, options);
33
- //syncLog(`Forms API Response: ${prop}${subProp ? '.' + subProp : ''}.${method}, Status: ${response?.status}, Data: ${JSON.stringify(response?.data)}`);
34
- } catch (err) {
35
- error = err;
36
- response = err.response;
37
- syncError(`Forms API Error Response: ${prop}${subProp ? '.' + subProp : ''}.${method}, Status: ${response?.status}, Error: ${JSON.stringify(error)}`);
38
- }
39
-
40
- const isRetryable = [429, 500, 503].includes(response?.status) || error?.code == 429;
41
-
42
- if (isRetryable && i < maxRetries - 1) {
43
- const jitter = Math.floor(Math.random() * 1000);
44
- syncWarn(`Retryable error on Forms API call ${prop}${subProp ? '.' + subProp : ''}.${method} (status: ${response?.status}). Retrying in ${delay + jitter}ms...`);
45
- await sleep(delay + jitter);
46
- delay *= 2;
47
- continue;
48
- }
49
-
50
- if (error || isRetryable) {
51
- syncError(`Failed in sxForms for ${prop}${subProp ? '.' + subProp : ''}.${method}`, error);
52
- return { data: null, response: responseSyncify(response) };
17
+ return sxRetry(Auth, tag, async () => {
18
+ // Access the base property (e.g., 'forms'), then the sub-property if it exists (e.g., 'responses').
19
+ let callish = apiClient[prop];
20
+ if (subProp) {
21
+ callish = callish[subProp];
53
22
  }
54
- return { data: response.data, response: responseSyncify(response) };
55
- }
23
+ return callish[method](params, options);
24
+ });
56
25
  };
@@ -6,51 +6,23 @@
6
6
  * - arguments and returns must be serializable ie. primitives or plain objects
7
7
  */
8
8
 
9
- import { responseSyncify } from './auth.js';
10
- import { syncWarn, syncError } from './workersync/synclogger.js';
9
+ import { sxRetry } from './sxretry.js';
11
10
  import { getGmailApiClient } from '../services/advgmail/gmailapis.js';
12
11
 
13
- const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
14
-
15
12
  export const sxGmail = async (Auth, { subProp, prop, method, params, options }) => {
16
13
 
17
14
  const apiClient = getGmailApiClient();
18
- const maxRetries = 7;
19
- let delay = 1777;
20
15
  const methodName = subProp ? `${prop}.${subProp}.${method}` : `${prop}.${method}`;
16
+ const tag = `sxGmail for ${methodName}`;
21
17
 
22
- for (let i = 0; i < maxRetries; i++) {
23
- let response;
24
- let error;
25
- try {
26
- const callish = subProp ? apiClient[prop][subProp] : apiClient[prop];
27
- response = await callish[method](params, options);
28
- } catch (err) {
29
- error = err;
30
- response = err.response;
31
- }
32
-
33
- const isRetryable = [429, 500, 503].includes(response?.status) || error?.code == 429;
34
-
35
- if (isRetryable && i < maxRetries - 1) {
36
- const jitter = Math.floor(Math.random() * 1000);
37
- syncWarn(`Retryable error on Gmail API call ${methodName} (status: ${response?.status}). Retrying in ${delay + jitter}ms...`);
38
- await sleep(delay + jitter);
39
- delay *= 2;
40
- continue;
41
- }
42
-
43
- if (error || isRetryable) {
18
+ return sxRetry(Auth, tag, async () => {
19
+ const callish = subProp ? apiClient[prop][subProp] : apiClient[prop];
20
+ return callish[method](params, options);
21
+ }, {
22
+ skipLog: (error, response) => {
44
23
  // Don't log 404, 409, or 400 as an error.
45
24
  // 400 (Invalid delete request) happens when we try to delete an ID as a label but it's not a label.
46
- if (response?.status !== 404 && response?.status !== 409 && response?.status !== 400) {
47
- syncError(`Failed in sxGmail for ${methodName}`, error);
48
- }
49
- return { data: null, response: responseSyncify(response) };
25
+ return response?.status === 404 || response?.status === 409 || response?.status === 400;
50
26
  }
51
- return {
52
- data: response.data,
53
- response: responseSyncify(response)
54
- };
55
- }
27
+ });
56
28
  };
@@ -0,0 +1,79 @@
1
+ import { responseSyncify } from './auth.js';
2
+ import { syncWarn, syncError } from './workersync/synclogger.js';
3
+
4
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
5
+
6
+ /**
7
+ * Shared retry logic for worker-based API calls
8
+ * @param {object} Auth the Auth object
9
+ * @param {string} tag for logging
10
+ * @param {function} func the function to execute
11
+ * @param {object} [options] options
12
+ * @param {number} [options.maxRetries=7] max retries
13
+ * @param {number} [options.initialDelay=1777] initial delay
14
+ * @param {function} [options.extraRetryCheck] extra check for retryability
15
+ * @param {function} [options.skipLog] check to skip syncError logging
16
+ * @returns {object} { data, response }
17
+ */
18
+ export const sxRetry = async (Auth, tag, func, options = {}) => {
19
+ const {
20
+ maxRetries = 7,
21
+ initialDelay = 1777,
22
+ extraRetryCheck = () => false,
23
+ skipLog = () => false
24
+ } = options;
25
+
26
+ let delay = initialDelay;
27
+
28
+ for (let i = 0; i < maxRetries; i++) {
29
+ let response;
30
+ let error;
31
+
32
+ try {
33
+ response = await func();
34
+ } catch (err) {
35
+ error = err;
36
+ response = err.response;
37
+ }
38
+
39
+ const redoCodes = [429, 500, 503, 408, 401]
40
+ const isRetryable = redoCodes.includes(error?.code) ||
41
+ redoCodes.includes(response?.status) ||
42
+ error?.code === 'ETIMEDOUT' ||
43
+ error?.code === 'ECONNRESET' ||
44
+ error?.cause?.code === 'ETIMEDOUT' ||
45
+ error?.cause?.code === 'ECONNRESET' ||
46
+ error?.message?.includes('ETIMEDOUT') ||
47
+ error?.message?.includes('ECONNRESET') ||
48
+ (response?.status === 403 && (
49
+ error?.message?.toLowerCase().includes('usage limit') ||
50
+ error?.message?.toLowerCase().includes('rate limit') ||
51
+ error?.errors?.some(e => ['rateLimitExceeded', 'userRateLimitExceeded', 'calendarUsageLimitsExceeded'].includes(e.reason))
52
+ )) ||
53
+ extraRetryCheck(error, response);
54
+
55
+ if (isRetryable && i < maxRetries - 1) {
56
+ const isAuthError = error?.code === 401 || response?.status === 401;
57
+ if (isAuthError) {
58
+ Auth.invalidateToken();
59
+ syncWarn(`Authentication error (401) on ${tag}. Invalidated token and retrying immediately...`);
60
+ } else {
61
+ const jitter = Math.floor(Math.random() * 1000);
62
+ const totalDelay = delay + jitter;
63
+ syncWarn(`Retryable error on ${tag} (status: ${response?.status || error?.code}). Retrying in ${totalDelay}ms...`);
64
+ await sleep(totalDelay);
65
+ delay *= 2;
66
+ }
67
+ continue;
68
+ }
69
+
70
+ if (error) {
71
+ if (!skipLog(error, response)) {
72
+ syncError(`Failed in ${tag}`, error);
73
+ }
74
+ return { data: null, response: responseSyncify(response) };
75
+ }
76
+
77
+ return { data: response.data, response: responseSyncify(response) };
78
+ }
79
+ };
@@ -6,47 +6,16 @@
6
6
  * - arguments and returns must be serializable ie. primitives or plain objects
7
7
  */
8
8
 
9
- import { responseSyncify } from './auth.js';
10
- import { syncWarn, syncError } from './workersync/synclogger.js';
9
+ import { sxRetry } from './sxretry.js';
11
10
  import { getSheetsApiClient } from '../services/advsheets/shapis.js';
12
11
 
13
- const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
14
-
15
12
  export const sxSheets = async (Auth, { subProp, prop, method, params, options }) => {
16
13
 
17
14
  const apiClient = getSheetsApiClient();
18
- const maxRetries = 7;
19
- let delay = 1777;
20
-
21
- for (let i = 0; i < maxRetries; i++) {
22
- let response;
23
- let error;
24
- try {
25
- const callish = subProp ? apiClient[prop][subProp] : apiClient[prop];
26
- response = await callish[method](params, options);
27
- } catch (err) {
28
- error = err;
29
- response = err.response;
30
- }
31
-
32
- const isRetryable = [429, 500, 503].includes(response?.status) || error?.code == 429;
33
-
34
- if (isRetryable && i < maxRetries - 1) {
35
- // add a random jitter to avoid thundering herd
36
- const jitter = Math.floor(Math.random() * 1000);
37
- syncWarn(`Retryable error on Sheets API call ${prop}.${method} (status: ${response?.status}). Retrying in ${delay + jitter}ms...`);
38
- await sleep(delay + jitter);
39
- delay *= 2;
40
- continue;
41
- }
15
+ const tag = `sxSheets for ${prop}.${method}`;
42
16
 
43
- if (error || isRetryable) {
44
- syncError(`Failed in sxSheets for ${prop}.${method}`, error);
45
- return { data: null, response: responseSyncify(response) };
46
- }
47
- return {
48
- data: response.data,
49
- response: responseSyncify(response)
50
- };
51
- }
17
+ return sxRetry(Auth, tag, async () => {
18
+ const callish = subProp ? apiClient[prop][subProp] : apiClient[prop];
19
+ return callish[method](params, options);
20
+ });
52
21
  };
@@ -6,12 +6,9 @@
6
6
  * - arguments and returns must be serializable ie. primitives or plain objects
7
7
  */
8
8
 
9
- import { responseSyncify } from './auth.js';
10
- import { syncWarn, syncError } from './workersync/synclogger.js';
9
+ import { sxRetry } from './sxretry.js';
11
10
  import { getSlidesApiClient } from '../services/advslides/slapis.js';
12
11
 
13
- const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
14
-
15
12
  /**
16
13
  * sync a call to slides api
17
14
  * @param {object} Auth the auth object
@@ -25,37 +22,9 @@ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
25
22
  export const sxSlides = async (Auth, { prop, method, params, options = {} }) => {
26
23
 
27
24
  const apiClient = getSlidesApiClient();
25
+ const tag = `sxSlides for ${prop}.${method}`;
28
26
 
29
- const maxRetries = 7;
30
- let delay = 1777;
31
-
32
- for (let i = 0; i < maxRetries; i++) {
33
- let response;
34
- let error;
35
-
36
- try {
37
- const callish = apiClient[prop];
38
- response = await callish[method](params, options);
39
- } catch (err) {
40
- error = err;
41
- response = err.response;
42
- }
43
-
44
- const isRetryable = [429, 500, 503].includes(response?.status) || error?.code == 429;
45
-
46
- if (isRetryable && i < maxRetries - 1) {
47
- // add a random jitter to avoid thundering herd
48
- const jitter = Math.floor(Math.random() * 1000);
49
- syncWarn(`Retryable error on Slides API call ${prop}.${method} (status: ${response?.status}). Retrying in ${delay + jitter}ms...`);
50
- await sleep(delay + jitter);
51
- delay *= 2;
52
- continue;
53
- }
54
-
55
- if (error || isRetryable) {
56
- syncError(`Failed in sxSlides for ${prop}.${method}`, error);
57
- return { data: null, response: responseSyncify(response) };
58
- }
59
- return { data: response.data, response: responseSyncify(response) };
60
- }
27
+ return sxRetry(Auth, tag, async () => {
28
+ return apiClient[prop][method](params, options);
29
+ });
61
30
  };
@@ -0,0 +1,15 @@
1
+ import { Auth } from './auth.js'
2
+
3
+ /**
4
+ * fetch effective user access token
5
+ */
6
+ export const sxGetAccessToken = async () => {
7
+ return await Auth.getAccessToken()
8
+ }
9
+
10
+ export const sxGetAccessTokenInfo = async () => {
11
+ return await Auth.getAccessTokenInfo()
12
+ }
13
+ export const sxGetSourceAccessTokenInfo = async () => {
14
+ return await Auth.getSourceAccessTokenInfo()
15
+ }
@@ -270,11 +270,14 @@ const fxInit = ({
270
270
  // this is the path of the runing main process
271
271
  const mainDir = path.dirname(process.argv[1]);
272
272
 
273
+ // Resolve defaults relative to mainDir if they are relative
274
+ const resolve = (p) => path.isAbsolute(p) ? p : path.resolve(mainDir, p);
275
+
273
276
  // because this is all run in a synced subprocess it's not an async result
274
277
  const synced = callSync("sxInit", {
275
- claspPath,
276
- settingsPath,
277
- manifestPath,
278
+ claspPath: resolve(claspPath),
279
+ settingsPath: resolve(settingsPath),
280
+ manifestPath: resolve(manifestPath),
278
281
  mainDir,
279
282
  cachePath,
280
283
  propertiesPath,
@@ -283,22 +286,22 @@ const fxInit = ({
283
286
 
284
287
  const {
285
288
  scopes,
289
+ activeUser,
290
+ effectiveUser,
286
291
  projectId,
287
- tokenInfo,
288
- accessToken,
289
292
  settings,
290
293
  manifest,
291
294
  clasp,
292
295
  } = synced;
293
296
 
294
- // set these values from the subprocess for the main project
297
+ // set these values from the subprocess into the main project version of auth
295
298
  Auth.setProjectId(projectId);
296
- //Auth.setAuth(scopes)
297
- Auth.setTokenInfo(tokenInfo);
298
- //Auth.setAccessToken(accessToken)
299
299
  Auth.setSettings(settings);
300
300
  Auth.setClasp(clasp);
301
301
  Auth.setManifest(manifest);
302
+ Auth.setActiveUser(activeUser);
303
+ Auth.setEffectiveUser(effectiveUser);
304
+ Auth.setTokenScopes(scopes);
302
305
  return synced;
303
306
  };
304
307
 
@@ -367,6 +370,17 @@ const fxFetchAll = (requests, responseFields) => {
367
370
  return callSync("sxFetchAll", requests, responseFields);
368
371
  };
369
372
 
373
+ const fxGetAccessToken = () => {
374
+ return callSync("sxGetAccessToken");
375
+ };
376
+
377
+ const fxGetAccessTokenInfo = () => {
378
+ return callSync("sxGetAccessTokenInfo");
379
+ };
380
+ const fxGetSourceAccessTokenInfo = () => {
381
+ return callSync("sxGetSourceAccessTokenInfo");
382
+ };
383
+
370
384
  const fxSheets = (args) =>
371
385
  fxGeneric({
372
386
  ...args,
@@ -430,5 +444,8 @@ export const Syncit = {
430
444
  fxForms,
431
445
  fxGmail,
432
446
  fxCalendar,
433
- fxDriveExport
447
+ fxDriveExport,
448
+ fxGetAccessToken,
449
+ fxGetAccessTokenInfo,
450
+ fxGetSourceAccessTokenInfo
434
451
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  import is from '@sindresorhus/is';
4
4
  import { assert } from '@sindresorhus/is'
5
- import {slogger} from './slogger.js'
5
+ import { slogger } from './slogger.js'
6
6
 
7
7
  const isNU = (item) => is.null(item) || is.undefined(item)
8
8
 
@@ -171,6 +171,18 @@ export const mergeParamStrings = (...args) => {
171
171
  }).sort().join(",")
172
172
  }
173
173
 
174
+ /**
175
+ * translated field names from v3 to v2
176
+ * @param {string} fields a comma separated fields string
177
+ * @returns {string} the modified string
178
+ */
179
+ export const translateFieldsToV2 = (fields) => {
180
+ if (!is.string(fields)) return fields
181
+ return fields
182
+ .replace(/\bcreatedTime\b/g, 'createdDate')
183
+ .replace(/\bmodifiedTime\b/g, 'modifiedDate')
184
+ }
185
+
174
186
  const capital = (str) => str.substring(0, 1).toUpperCase() + str.substring(1)
175
187
  const unCapital = (str) => str.substring(0, 1).toLowerCase() + str.substring(1)
176
188
 
@@ -10,5 +10,7 @@ export * from "../sxauth.js";
10
10
  export * from "../sxgmail.js";
11
11
  export * from "../sxcalendar.js";
12
12
  export * from "../sxxlsx.js";
13
+ export * from "../sxtoken.js";
14
+
13
15
 
14
16