@mcpher/gas-fakes 2.3.18 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -32
- package/package.json +1 -2
- package/src/cli/app.js +30 -2
- package/src/cli/server.js +32 -0
- package/src/cli/setup.js +24 -0
- package/src/cli/togas.js +176 -0
- package/src/index.js +2 -0
- package/src/services/common/fakeui.js +45 -0
- package/src/services/content/app.js +3 -0
- package/src/services/content/contentservice.js +14 -0
- package/src/services/content/textoutput.js +45 -0
- package/src/services/documentapp/fakedocumentapp.js +1 -1
- package/src/services/enums/contentenums.js +15 -0
- package/src/services/enums/htmlenums.js +13 -0
- package/src/services/enums/scriptenums.js +6 -0
- package/src/services/formapp/fakeformapp.js +5 -0
- package/src/services/html/app.js +9 -0
- package/src/services/html/consumerworker.js +129 -0
- package/src/services/html/googlescriptrun.js +91 -0
- package/src/services/html/htmloutput.js +127 -0
- package/src/services/html/htmloutputmetatag.js +14 -0
- package/src/services/html/htmlservice.js +94 -0
- package/src/services/html/htmltemplate.js +63 -0
- package/src/services/html/serverworker.js +135 -0
- package/src/services/html/webapp.js +266 -0
- package/src/services/html/worker.js +63 -0
- package/src/services/libhandlerapp/fakelibrary.js +2 -2
- package/src/services/scriptapp/app.js +44 -0
- package/src/services/scriptapp/fakeauthorizationinfo.js +22 -0
- package/src/services/slidesapp/fakeslidesapp.js +5 -0
- package/src/services/spreadsheetapp/fakebooleancondition.js +14 -2
- package/src/services/spreadsheetapp/fakegradientcondition.js +1 -1
- package/src/services/spreadsheetapp/fakeovergridimage.js +25 -0
- package/src/services/spreadsheetapp/fakesheet.js +23 -1
- package/src/services/spreadsheetapp/fakespreadsheet.js +68 -11
- package/src/services/spreadsheetapp/fakespreadsheetapp.js +70 -9
- package/src/services/stores/fakestores.js +7 -0
- package/src/support/auth.js +2 -0
- package/src/support/proxies.js +1 -1
- package/src/support/sxauth.js +20 -12
- package/src/support/utils.js +480 -200
- package/src/support/workersync/sxhtml.js +8 -0
- package/src/support/workersync/synchronizer.js +8 -1
- package/src/support/workersync/worker.js +5 -0
- package/api-docs/kdrive_api.json +0 -69958
- package/appsscript.json +0 -102
- package/gf_agent/README.md +0 -101
- package/gf_agent/SKILL.md +0 -484
- package/gf_agent/documentation.md +0 -105
- package/gf_agent/gf-agent-contributor/SKILL.md +0 -56
- package/gf_agent/index.md +0 -21
- package/gf_agent/knowledge/00-execution-context.md +0 -5
- package/gf_agent/knowledge/01-drive.md +0 -12
- package/gf_agent/knowledge/02-syntax.md +0 -14
- package/gf_agent/knowledge/03-auth.md +0 -15
- package/gf_agent/knowledge/04-advanced.md +0 -46
- package/gf_agent/knowledge/05-sheets-forms.md +0 -27
- package/gf_agent/knowledge/06-jdbc-cloudsql.md +0 -21
- package/gf_agent/knowledge/07-jdbc-auth-details.md +0 -30
- package/gf_agent/knowledge/08-docs-limitations.md +0 -4
- package/gf_agent/knowledge/09-orchestrator-pattern.md +0 -55
- package/gf_agent/knowledge/10-sandbox-security.md +0 -62
- package/gf_agent/knowledge/11-chart-builder-limitations.md +0 -15
- package/gf_agent/knowledge/12-gmail-eventual-consistency.md +0 -13
- package/gf_agent/knowledge/13-advanced-services-discovery.md +0 -29
- package/gf_agent/knowledge/14-utilities-parity.md +0 -13
- package/gf_agent/knowledge/15-logging-efficiency.md +0 -15
- package/gf_agent/knowledge/README.md +0 -16
- package/gf_agent/scripts/SKILL.template.md +0 -63
- package/gf_agent/scripts/builder.js +0 -118
- package/gf_agent/skills/base.md +0 -156
- package/gf_agent/skills/cache.md +0 -20
- package/gf_agent/skills/calendar.md +0 -780
- package/gf_agent/skills/charts.md +0 -127
- package/gf_agent/skills/document.md +0 -6752
- package/gf_agent/skills/drive.md +0 -423
- package/gf_agent/skills/forms.md +0 -4036
- package/gf_agent/skills/gmail.md +0 -576
- package/gf_agent/skills/jdbc.md +0 -3101
- package/gf_agent/skills/lock.md +0 -20
- package/gf_agent/skills/properties.md +0 -19
- package/gf_agent/skills/script.md +0 -50
- package/gf_agent/skills/slides.md +0 -5054
- package/gf_agent/skills/spreadsheet.md +0 -56075
- package/gf_agent/skills/urlfetch.md +0 -28
- package/gf_agent/skills/utilities.md +0 -50
- package/gf_agent/skills/xml.md +0 -270
- package/skills-lock.json +0 -10
- package/src/services/documentapp/fakeui.js +0 -27
|
@@ -35,13 +35,14 @@ export class FakeSpreadsheet {
|
|
|
35
35
|
constructor(file) {
|
|
36
36
|
// when we insert/delete sheets row/cols we update this metadata too
|
|
37
37
|
this.__meta = file;
|
|
38
|
+
this.__activeRange = null;
|
|
39
|
+
this.__activeSheet = null;
|
|
38
40
|
|
|
39
41
|
// may of these props can be picked up from the Drive API, so we'll look as a file too
|
|
40
42
|
this.__file = DriveApp.getFileById(file.spreadsheetId);
|
|
41
43
|
|
|
42
44
|
const props = [
|
|
43
45
|
"getSpreadsheetTheme",
|
|
44
|
-
"setActiveSheet",
|
|
45
46
|
|
|
46
47
|
"getBandings",
|
|
47
48
|
"getDataSources",
|
|
@@ -102,12 +103,7 @@ export class FakeSpreadsheet {
|
|
|
102
103
|
"isReadable",
|
|
103
104
|
"isWritable",
|
|
104
105
|
"getSelection",
|
|
105
|
-
"setActiveRangeList",
|
|
106
|
-
"setActiveRange",
|
|
107
106
|
"getActiveRangeList",
|
|
108
|
-
"getCurrentCell",
|
|
109
|
-
"setCurrentCell",
|
|
110
|
-
"getActiveRange",
|
|
111
107
|
"deleteRow",
|
|
112
108
|
"hideRow",
|
|
113
109
|
"appendRow",
|
|
@@ -133,9 +129,7 @@ export class FakeSpreadsheet {
|
|
|
133
129
|
"getFrozenColumns",
|
|
134
130
|
"unhideColumn",
|
|
135
131
|
"insertColumnsBefore",
|
|
136
|
-
"setActiveSelection",
|
|
137
132
|
"getDataSourceFormulas",
|
|
138
|
-
"insertImage",
|
|
139
133
|
"getSheetPermissions",
|
|
140
134
|
"insertColumnBefore",
|
|
141
135
|
|
|
@@ -160,16 +154,79 @@ export class FakeSpreadsheet {
|
|
|
160
154
|
return notYetImplemented(f);
|
|
161
155
|
};
|
|
162
156
|
});
|
|
157
|
+
}
|
|
163
158
|
|
|
159
|
+
setActiveRange(range) {
|
|
160
|
+
this.__activeRange = range;
|
|
161
|
+
this.__activeSheet = range.getSheet();
|
|
162
|
+
this.__currentCell = range.getCell(1, 1);
|
|
163
|
+
|
|
164
|
+
// Sync with SpreadsheetApp if this is the active spreadsheet
|
|
165
|
+
const app = SpreadsheetApp;
|
|
166
|
+
if (app && app.getActiveSpreadsheet() === this) {
|
|
167
|
+
app.setActiveSpreadsheet(this);
|
|
168
|
+
}
|
|
169
|
+
return range;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
setActiveRangeList(rangeList) {
|
|
173
|
+
const ranges = rangeList.getRanges();
|
|
174
|
+
if (ranges && ranges.length > 0) {
|
|
175
|
+
this.setActiveRange(ranges[ranges.length - 1]);
|
|
176
|
+
}
|
|
177
|
+
return rangeList;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
setActiveSelection(rangeOrA1Notation) {
|
|
181
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "Spreadsheet.setActiveSelection");
|
|
182
|
+
if (nargs !== 1) matchThrow();
|
|
183
|
+
|
|
184
|
+
let range;
|
|
185
|
+
if (is.string(rangeOrA1Notation)) {
|
|
186
|
+
range = this.getRange(rangeOrA1Notation);
|
|
187
|
+
} else {
|
|
188
|
+
range = rangeOrA1Notation;
|
|
189
|
+
}
|
|
190
|
+
return this.setActiveRange(range);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
getActiveRange() {
|
|
194
|
+
return this.__activeRange || this.getActiveSheet().getRange('A1');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
getCurrentCell() {
|
|
198
|
+
return this.__currentCell || this.getActiveSheet().getRange('A1');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
setCurrentCell(cell) {
|
|
202
|
+
this.__currentCell = cell;
|
|
203
|
+
this.__activeSheet = cell.getSheet();
|
|
204
|
+
// Setting current cell does not change the active range, just the cell within it.
|
|
205
|
+
// However, if there is no active range, it becomes the active range.
|
|
206
|
+
if (!this.__activeRange) {
|
|
207
|
+
this.__activeRange = cell;
|
|
208
|
+
}
|
|
209
|
+
return cell;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
setActiveSheet(sheet, restoreSelection) {
|
|
213
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "Spreadsheet.setActiveSheet");
|
|
214
|
+
if (nargs < 1 || nargs > 2) matchThrow();
|
|
215
|
+
this.__activeSheet = sheet;
|
|
216
|
+
return sheet;
|
|
164
217
|
}
|
|
165
218
|
|
|
166
|
-
// note this is a workaround as we don't have the concept of active sheet in a non bound document
|
|
167
|
-
// so instead we'll just get the first sheet for now
|
|
168
|
-
// TODO - something better
|
|
169
219
|
getActiveSheet() {
|
|
220
|
+
if (this.__activeSheet) return this.__activeSheet;
|
|
170
221
|
return this.__getFirstSheet();
|
|
171
222
|
}
|
|
172
223
|
|
|
224
|
+
insertImage(blobSourceOrUrl, column, row, offsetX, offsetY) {
|
|
225
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "Spreadsheet.insertImage");
|
|
226
|
+
if (nargs < 3 || nargs > 5) matchThrow();
|
|
227
|
+
return this.getActiveSheet().insertImage(blobSourceOrUrl, column, row, offsetX, offsetY);
|
|
228
|
+
}
|
|
229
|
+
|
|
173
230
|
addViewer(emailAddress) {
|
|
174
231
|
this.__file.addViewer(emailAddress);
|
|
175
232
|
return this;
|
|
@@ -16,6 +16,7 @@ import { newFakeConditionalFormatRuleBuilder } from "./fakeconditionalformatrule
|
|
|
16
16
|
import { newFakeDataSourceSpecBuilder } from "./fakedatasourcespecbuilder.js";
|
|
17
17
|
import { newFakeTextFinder } from "./faketextfinder.js";
|
|
18
18
|
import { newFakeCellImageBuilder } from "./fakecellimagebuilder.js";
|
|
19
|
+
import { newFakeUi } from "../common/fakeui.js";
|
|
19
20
|
|
|
20
21
|
import * as Enums from "../enums/sheetsenums.js";
|
|
21
22
|
|
|
@@ -81,16 +82,8 @@ export class FakeSpreadsheetApp {
|
|
|
81
82
|
|
|
82
83
|
const props = [
|
|
83
84
|
"getActive",
|
|
84
|
-
"getActiveSheet",
|
|
85
|
-
"getCurrentCell",
|
|
86
|
-
"getActiveRange",
|
|
87
85
|
"getActiveRangeList",
|
|
88
86
|
"getSelection",
|
|
89
|
-
"setActiveSheet",
|
|
90
|
-
"setCurrentCell",
|
|
91
|
-
"setActiveRange",
|
|
92
|
-
"setActiveRangeList",
|
|
93
|
-
"getUi",
|
|
94
87
|
|
|
95
88
|
"ChartAggregationType",
|
|
96
89
|
"ChartTransformationType",
|
|
@@ -102,6 +95,11 @@ export class FakeSpreadsheetApp {
|
|
|
102
95
|
};
|
|
103
96
|
});
|
|
104
97
|
}
|
|
98
|
+
|
|
99
|
+
getUi() {
|
|
100
|
+
return newFakeUi();
|
|
101
|
+
}
|
|
102
|
+
|
|
105
103
|
toString() {
|
|
106
104
|
return "SpreadsheetApp";
|
|
107
105
|
}
|
|
@@ -124,8 +122,11 @@ export class FakeSpreadsheetApp {
|
|
|
124
122
|
if (this.__activeSpreadsheet) return this.__activeSpreadsheet;
|
|
125
123
|
// because this is a faked container bound app, we need to get the documentId from the config file
|
|
126
124
|
const documentId = Auth.getDocumentId();
|
|
125
|
+
console.log('Worker Auth.getDocumentId():', documentId);
|
|
127
126
|
if (documentId) {
|
|
128
|
-
|
|
127
|
+
const ss = this.openById(documentId);
|
|
128
|
+
//console.log('Worker openById result:', ss);
|
|
129
|
+
return ss;
|
|
129
130
|
}
|
|
130
131
|
return null;
|
|
131
132
|
}
|
|
@@ -135,6 +136,24 @@ export class FakeSpreadsheetApp {
|
|
|
135
136
|
return this;
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
getActiveSheet() {
|
|
140
|
+
const ss = this.getActiveSpreadsheet();
|
|
141
|
+
if (ss) return ss.getActiveSheet();
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
setActiveSheet(sheet, restoreSelection) {
|
|
146
|
+
const { nargs, matchThrow } = signatureArgs(arguments, "SpreadsheetApp.setActiveSheet");
|
|
147
|
+
if (nargs < 1 || nargs > 2) matchThrow();
|
|
148
|
+
|
|
149
|
+
// According to GAS docs, setActiveSheet on SpreadsheetApp also sets the active spreadsheet
|
|
150
|
+
const ss = sheet.getParent();
|
|
151
|
+
if (ss) {
|
|
152
|
+
this.setActiveSpreadsheet(ss);
|
|
153
|
+
ss.setActiveSheet(sheet, restoreSelection);
|
|
154
|
+
}
|
|
155
|
+
return sheet;
|
|
156
|
+
}
|
|
138
157
|
|
|
139
158
|
enableBigQueryExecution() {
|
|
140
159
|
const { nargs, matchThrow } = signatureArgs(
|
|
@@ -145,6 +164,48 @@ export class FakeSpreadsheetApp {
|
|
|
145
164
|
// This is a no-op in the fake environment, as there's no real execution to enable.
|
|
146
165
|
}
|
|
147
166
|
|
|
167
|
+
getActiveRange() {
|
|
168
|
+
const ss = this.getActiveSpreadsheet();
|
|
169
|
+
if (ss) return ss.getActiveRange();
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
setActiveRange(range) {
|
|
174
|
+
const ss = range.getSheet().getParent();
|
|
175
|
+
if (ss) {
|
|
176
|
+
this.setActiveSpreadsheet(ss);
|
|
177
|
+
return ss.setActiveRange(range);
|
|
178
|
+
}
|
|
179
|
+
return range;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
setActiveRangeList(rangeList) {
|
|
183
|
+
const ranges = rangeList.getRanges();
|
|
184
|
+
if (ranges && ranges.length > 0) {
|
|
185
|
+
const ss = ranges[0].getSheet().getParent();
|
|
186
|
+
if (ss) {
|
|
187
|
+
this.setActiveSpreadsheet(ss);
|
|
188
|
+
return ss.setActiveRangeList(rangeList);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return rangeList;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
getCurrentCell() {
|
|
195
|
+
const ss = this.getActiveSpreadsheet();
|
|
196
|
+
if (ss) return ss.getCurrentCell();
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
setCurrentCell(cell) {
|
|
201
|
+
const ss = cell.getSheet().getParent();
|
|
202
|
+
if (ss) {
|
|
203
|
+
this.setActiveSpreadsheet(ss);
|
|
204
|
+
return ss.setCurrentCell(cell);
|
|
205
|
+
}
|
|
206
|
+
return cell;
|
|
207
|
+
}
|
|
208
|
+
|
|
148
209
|
enableAllDataSourcesExecution() {
|
|
149
210
|
const { nargs, matchThrow } = signatureArgs(
|
|
150
211
|
arguments,
|
|
@@ -111,6 +111,7 @@ class FakePropertiesService {
|
|
|
111
111
|
constructor(type) {
|
|
112
112
|
this.kind = ServiceKind.PROPERTIES
|
|
113
113
|
this.type = type
|
|
114
|
+
Syncit.fxGetAccessTokenInfo();
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
/**
|
|
@@ -147,6 +148,7 @@ class FakeCacheService {
|
|
|
147
148
|
constructor(type) {
|
|
148
149
|
this.kind = ServiceKind.CACHE
|
|
149
150
|
this.type = type
|
|
151
|
+
Syncit.fxGetAccessTokenInfo();
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
/**
|
|
@@ -191,6 +193,11 @@ export const newFakeService = (kind) => {
|
|
|
191
193
|
const selectCache = (domain, kind, defaultExpirationSeconds) => {
|
|
192
194
|
// actually we might be overriding the type of service
|
|
193
195
|
domain = validateProp(domain, StoreDomain, 'store_domain')
|
|
196
|
+
|
|
197
|
+
if (domain === StoreDomain.USER && !Auth.getUserId()) {
|
|
198
|
+
throw new Error('User Properties/Cache requested, but no authenticated user identity was found. Ensure you have authenticated via \'gas-fakes auth\'.');
|
|
199
|
+
}
|
|
200
|
+
|
|
194
201
|
const which = whichCache()
|
|
195
202
|
if (which.type === "UPSTASH") {
|
|
196
203
|
const models = getStoreModels()
|
package/src/support/auth.js
CHANGED
|
@@ -6,6 +6,7 @@ import { clearFileCache } from "./filecache.js";
|
|
|
6
6
|
|
|
7
7
|
// Multi-identity storage
|
|
8
8
|
export const _identities = new Map();
|
|
9
|
+
|
|
9
10
|
// Prefer 'google' as the default platform if it is authorized in the environment
|
|
10
11
|
let _platform = process.env.GF_PLATFORM_AUTH ? (process.env.GF_PLATFORM_AUTH.includes('google') ? 'google' : process.env.GF_PLATFORM_AUTH.split(',')[0]) : 'google';
|
|
11
12
|
let _manifest = null;
|
|
@@ -361,6 +362,7 @@ export const Auth = {
|
|
|
361
362
|
getAuthedScopes,
|
|
362
363
|
getScriptId,
|
|
363
364
|
getDocumentId,
|
|
365
|
+
getSettings,
|
|
364
366
|
setSettings,
|
|
365
367
|
getCachePath,
|
|
366
368
|
getPropertiesPath,
|
package/src/support/proxies.js
CHANGED
package/src/support/sxauth.js
CHANGED
|
@@ -52,6 +52,8 @@ export const sxInit = async ({ manifestPath, claspPath, settingsPath, cachePath,
|
|
|
52
52
|
getIfExists(claspFile)
|
|
53
53
|
])
|
|
54
54
|
|
|
55
|
+
const manifestExists = Object.keys(manifest).length > 0;
|
|
56
|
+
|
|
55
57
|
// Emulate manifest scopes from .env if missing or empty
|
|
56
58
|
if (!manifest.oauthScopes || manifest.oauthScopes.length === 0) {
|
|
57
59
|
const envScopes = Array.from(new Set([
|
|
@@ -65,10 +67,18 @@ export const sxInit = async ({ manifestPath, claspPath, settingsPath, cachePath,
|
|
|
65
67
|
manifest.timeZone = process.env.GF_TIMEZONE || "America/New_York";
|
|
66
68
|
}
|
|
67
69
|
if (!_loggedSummary) {
|
|
68
|
-
|
|
70
|
+
if (manifestExists) {
|
|
71
|
+
syncLog(`...appsscript.json found but 'oauthScopes' is missing. Emulating scopes from .env file`);
|
|
72
|
+
} else {
|
|
73
|
+
syncLog(`...appsscript.json missing. Emulating manifest using scopes from .env file`);
|
|
74
|
+
}
|
|
69
75
|
}
|
|
70
76
|
} else if (!_loggedSummary) {
|
|
71
|
-
|
|
77
|
+
if (manifestExists) {
|
|
78
|
+
syncWarn(`...Warning: appsscript.json found but 'oauthScopes' is missing, and no DEFAULT_SCOPES/EXTRA_SCOPES defined in .env. Downstream API calls may fail with 'insufficient authentication scopes'.`);
|
|
79
|
+
} else {
|
|
80
|
+
syncWarn(`...Warning: No appsscript.json found and no DEFAULT_SCOPES/EXTRA_SCOPES defined in .env. Downstream API calls may fail with 'insufficient authentication scopes'.`);
|
|
81
|
+
}
|
|
72
82
|
}
|
|
73
83
|
}
|
|
74
84
|
|
|
@@ -84,6 +94,7 @@ export const sxInit = async ({ manifestPath, claspPath, settingsPath, cachePath,
|
|
|
84
94
|
const identities = {};
|
|
85
95
|
|
|
86
96
|
// --- Google Auth Block ---
|
|
97
|
+
let finalScopes = [];
|
|
87
98
|
if (platforms.includes('google')) {
|
|
88
99
|
try {
|
|
89
100
|
// Ensure platform is set for info discovery
|
|
@@ -97,7 +108,7 @@ export const sxInit = async ({ manifestPath, claspPath, settingsPath, cachePath,
|
|
|
97
108
|
]
|
|
98
109
|
const scopeSet = new Set(scopes)
|
|
99
110
|
mandatoryScopes.forEach(scope => scopeSet.add(scope))
|
|
100
|
-
|
|
111
|
+
finalScopes = Array.from(scopeSet)
|
|
101
112
|
|
|
102
113
|
// Check for file-type scopes that also require Drive scope
|
|
103
114
|
const hasWorkspaceFileScope = finalScopes.some(s =>
|
|
@@ -153,27 +164,24 @@ export const sxInit = async ({ manifestPath, claspPath, settingsPath, cachePath,
|
|
|
153
164
|
|
|
154
165
|
// Provide guidance for Domain Wide Delegation issues
|
|
155
166
|
if (err.message.includes('unauthorized_client')) {
|
|
156
|
-
const clientId = Auth.getClientId();
|
|
157
167
|
const msg = [
|
|
158
168
|
"",
|
|
159
169
|
"=".repeat(80),
|
|
160
170
|
"GOOGLE AUTHENTICATION ERROR: unauthorized_client",
|
|
161
|
-
"
|
|
162
|
-
"",
|
|
163
|
-
`Your Service Account Client ID is: ${clientId || 'unknown (check your service account JSON file)'}`,
|
|
171
|
+
"The scopes defined in your appsscript.json are not currently authorized.",
|
|
164
172
|
"",
|
|
165
|
-
"The following scopes
|
|
173
|
+
"The following scopes are required:",
|
|
166
174
|
finalScopes.join(","),
|
|
167
175
|
"",
|
|
168
176
|
"To fix this:",
|
|
169
|
-
"1.
|
|
170
|
-
"2.
|
|
171
|
-
"3.
|
|
172
|
-
"4. Find/Add your Client ID and ensure the list of scopes above matches exactly.",
|
|
177
|
+
"1. Run 'gas-fakes init'",
|
|
178
|
+
"2. Run 'gas-fakes auth' to re-authenticate and sync your appsscript.json scopes.",
|
|
179
|
+
"3. If this is a Service Account with Domain-Wide Delegation (DWD), ensure these scopes are also added in the Google Admin Console (Security -> API Controls).",
|
|
173
180
|
"=".repeat(80),
|
|
174
181
|
""
|
|
175
182
|
].join("\n");
|
|
176
183
|
console.error(msg);
|
|
184
|
+
process.exit(1);
|
|
177
185
|
}
|
|
178
186
|
|
|
179
187
|
if (!platforms.includes('ksuite') && !platforms.includes('msgraph')) throw err;
|