@mcpher/gas-fakes 1.0.19 → 1.0.21
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 +63 -30
- package/gasmess/bruce/pbx.js +53 -2
- package/gprompts/gas-inventory.js +92 -0
- package/gprompts/gas-inventory.json +176 -0
- package/gprompts/inventory-list.json +1 -0
- package/gprompts/model.json +34 -0
- package/gprompts/package-lock.json +1103 -0
- package/gprompts/package.json +18 -0
- package/gprompts/temp_fetch.mjs +9 -0
- package/gprompts/update-progress.js +142 -0
- package/package.json +6 -2
- package/setup.sh +147 -0
- package/src/index.js +9 -2
- package/src/services/advdocs/app.js +4 -23
- package/src/services/advdrive/app.js +6 -28
- package/src/services/advforms/app.js +6 -25
- package/src/services/advgmail/app.js +11 -0
- package/src/services/advgmail/fakeadvgmail.js +39 -0
- package/src/services/advgmail/fakeadvgmaillabels.js +119 -0
- package/src/services/advgmail/fakeadvgmailusers.js +23 -0
- package/src/services/advgmail/gmailapis.js +15 -0
- package/src/services/advsheets/app.js +6 -26
- package/src/services/advslides/app.js +6 -28
- package/src/services/common/lazyloader.js +22 -0
- package/src/services/documentapp/app.js +8 -42
- package/src/services/documentapp/appenderhelpers.js +21 -23
- package/src/services/documentapp/elementhelpers.js +0 -1
- package/src/services/documentapp/elementoptions.js +22 -32
- package/src/services/documentapp/fakeelement.js +20 -3
- package/src/services/documentapp/fakelistitem.js +177 -28
- package/src/services/documentapp/fakeparagraph.js +194 -7
- package/src/services/documentapp/faketable.js +16 -0
- package/src/services/documentapp/faketablerow.js +15 -0
- package/src/services/documentapp/nrhelpers.js +1 -0
- package/src/services/documentapp/shadowdocument.js +10 -0
- package/src/services/driveapp/app.js +6 -28
- package/src/services/enums/gmailenums.js +8 -0
- package/src/services/formapp/app.js +5 -40
- package/src/services/gmailapp/app.js +11 -0
- package/src/services/gmailapp/fakegmailapp.js +35 -0
- package/src/services/gmailapp/fakegmaillabel.js +44 -0
- package/src/services/logger/app.js +8 -0
- package/src/services/logger/fakelogger.js +162 -0
- package/src/services/scriptapp/app.js +7 -1
- package/src/services/scriptapp/behavior.js +1 -1
- package/src/services/session/app.js +10 -0
- package/src/services/slidesapp/app.js +5 -40
- package/src/services/spreadsheetapp/app.js +6 -50
- package/src/services/spreadsheetapp/fakeprotection.js +6 -7
- package/src/services/spreadsheetapp/fakesheet.js +3 -4
- package/src/services/stores/app.js +0 -1
- package/src/services/urlfetchapp/app.js +0 -1
- package/src/services/utilities/app.js +6 -20
- package/src/support/gmailcacher.js +7 -0
- package/src/support/helpers.js +2 -2
- package/src/support/proxies.js +20 -1
- package/src/support/sxgmail.js +55 -0
- package/src/support/syncit.js +5 -2
- package/src/support/utils.js +46 -15
- package/src/support/workersync/sxfunctions.js +5 -10
- package/togas.bash +18 -5
- package/ghissues/image-size-inconsistency-issue.sh +0 -46
- package/ghissues/issue-formapp-create-title-inconsistency.sh +0 -51
- package/ghissues/issue-positioned-image.sh +0 -25
- package/ghissues/post-issue.sh +0 -53
- package/ghissues/protection-editors-issue.sh +0 -33
- package/ghissues/review-sandbox-listing-issue.sh +0 -45
- package/ghissues/sandbox-issue.sh +0 -31
- package/ghissues/setup-under-construction.sh +0 -107
- package/src/services/base/app.js +0 -33
- /package/{regenerate-progress-reports.sh → gprompts/regenerate-progress-reports.sh} +0 -0
- /package/src/services/{base → session}/fakesession.js +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gas-inventory",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Scrapes Google Apps Script documentation",
|
|
5
|
+
"main": "gas-inventory.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "node gas-inventory.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [],
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "ISC",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"cheerio": "^1.1.2",
|
|
15
|
+
"jsdom": "^24.0.0",
|
|
16
|
+
"node-fetch": "^3.3.2"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
const progressDir = path.join(__dirname, '..', 'progress');
|
|
11
|
+
const overallMdPath = path.join(progressDir, 'overall.md');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Calculates a percentage and formats it as a string.
|
|
15
|
+
* @param {number} completed - The number of completed items.
|
|
16
|
+
* @param {number} total - The total number of items.
|
|
17
|
+
* @returns {string} The formatted percentage string.
|
|
18
|
+
*/
|
|
19
|
+
const formatPercent = (completed, total) => {
|
|
20
|
+
if (total === 0) {
|
|
21
|
+
return '0%';
|
|
22
|
+
}
|
|
23
|
+
return `${Math.round((completed / total) * 100)}%`;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Parses a single markdown progress file to count classes and methods.
|
|
28
|
+
* @param {string} filePath - The path to the markdown file.
|
|
29
|
+
* @returns {Promise<{totalClasses: number, completedClasses: number, totalMethods: number, completedMethods: number}>}
|
|
30
|
+
*/
|
|
31
|
+
async function parseProgressFile(filePath) {
|
|
32
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
33
|
+
// Split the file into sections based on '## ' headings.
|
|
34
|
+
// The first element will be anything before the first class, which we ignore.
|
|
35
|
+
const classSections = content.split('\n## ').slice(1);
|
|
36
|
+
|
|
37
|
+
if (classSections.length === 0) {
|
|
38
|
+
return { totalClasses: 0, completedClasses: 0, totalMethods: 0, completedMethods: 0 };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let totalClasses = 0;
|
|
42
|
+
let completedClasses = 0;
|
|
43
|
+
let totalMethods = 0;
|
|
44
|
+
let completedMethods = 0;
|
|
45
|
+
for (const classContent of classSections) {
|
|
46
|
+
totalClasses++;
|
|
47
|
+
const classLines = classContent.split('\n');
|
|
48
|
+
let statusColumnIndex = -1;
|
|
49
|
+
let classTotalMethods = 0;
|
|
50
|
+
let classCompletedMethods = 0;
|
|
51
|
+
let isTableBody = false;
|
|
52
|
+
|
|
53
|
+
for (const line of classLines) {
|
|
54
|
+
const trimmedLine = line.trim();
|
|
55
|
+
|
|
56
|
+
if (!trimmedLine.startsWith('|')) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Find the header row to locate the 'status' column.
|
|
61
|
+
if (statusColumnIndex === -1 && trimmedLine.toLowerCase().includes('status') && !trimmedLine.includes('---')) {
|
|
62
|
+
const headers = trimmedLine.split('|').map(h => h.trim().toLowerCase());
|
|
63
|
+
statusColumnIndex = headers.indexOf('status');
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// The separator row marks the beginning of the table body.
|
|
68
|
+
if (trimmedLine.includes('---')) {
|
|
69
|
+
isTableBody = true;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// If we are in the table body and have a valid status column, count the method.
|
|
74
|
+
if (isTableBody && statusColumnIndex > -1) {
|
|
75
|
+
const columns = trimmedLine.split('|');
|
|
76
|
+
if (columns.length > statusColumnIndex) {
|
|
77
|
+
classTotalMethods++;
|
|
78
|
+
const statusCell = columns[statusColumnIndex].trim();
|
|
79
|
+
if (statusCell.toLowerCase().includes('completed')) {
|
|
80
|
+
classCompletedMethods++;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
totalMethods += classTotalMethods;
|
|
86
|
+
completedMethods += classCompletedMethods;
|
|
87
|
+
if (classTotalMethods > 0 && classTotalMethods === classCompletedMethods) {
|
|
88
|
+
completedClasses++;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return { totalClasses, completedClasses, totalMethods, completedMethods };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Main function to generate the overall progress summary.
|
|
97
|
+
*/
|
|
98
|
+
async function generateSummary() {
|
|
99
|
+
try {
|
|
100
|
+
const files = await fs.readdir(progressDir);
|
|
101
|
+
// Filter for .md files, excluding overall.md and other non-service files, case-insensitively
|
|
102
|
+
const mdFiles = files.filter(file =>
|
|
103
|
+
file.toLowerCase().endsWith('.md') &&
|
|
104
|
+
!['overall.md'].includes(file.toLowerCase())
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const allStats = [];
|
|
108
|
+
const grandTotal = { classes: 0, classesCompleted: 0, methods: 0, methodsCompleted: 0 };
|
|
109
|
+
|
|
110
|
+
for (const file of mdFiles) {
|
|
111
|
+
const serviceName = path.basename(file, path.extname(file));
|
|
112
|
+
const filePath = path.join(progressDir, file);
|
|
113
|
+
const stats = await parseProgressFile(filePath);
|
|
114
|
+
allStats.push({ name: serviceName, file, ...stats });
|
|
115
|
+
grandTotal.classes += stats.totalClasses;
|
|
116
|
+
grandTotal.classesCompleted += stats.completedClasses;
|
|
117
|
+
grandTotal.methods += stats.totalMethods;
|
|
118
|
+
grandTotal.methodsCompleted += stats.completedMethods;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
allStats.sort((a, b) => a.name.localeCompare(b.name));
|
|
122
|
+
|
|
123
|
+
let table = '# Overall Progress\n\n';
|
|
124
|
+
table += '| service | classes | methods | methods completed | %age |\n';
|
|
125
|
+
table += '| :--- | :---: | :---: | :---: | :---: |\n';
|
|
126
|
+
|
|
127
|
+
for (const stat of allStats) {
|
|
128
|
+
const methodPercent = formatPercent(stat.completedMethods, stat.totalMethods);
|
|
129
|
+
table += `| [${stat.name}](${stat.file}) | ${stat.totalClasses} | ${stat.totalMethods} | ${stat.completedMethods} | ${methodPercent} |\n`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const totalMethodPercent = formatPercent(grandTotal.methodsCompleted, grandTotal.methods);
|
|
133
|
+
table += `| **Total** | **${grandTotal.classes}** | **${grandTotal.methods}** | **${grandTotal.methodsCompleted}** | **${totalMethodPercent}** |\n`;
|
|
134
|
+
|
|
135
|
+
await fs.writeFile(overallMdPath, table);
|
|
136
|
+
console.log(`Successfully updated ${overallMdPath}`);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error('Failed to generate progress summary:', error);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
generateSummary();
|
package/package.json
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
"node": ">=20.11.0"
|
|
4
4
|
},
|
|
5
5
|
"dependencies": {
|
|
6
|
+
"@google-cloud/logging": "^11.2.1",
|
|
6
7
|
"@mcpher/fake-gasenum": "^1.0.2",
|
|
7
8
|
"@mcpher/unit": "^1.1.11",
|
|
8
9
|
"@sindresorhus/is": "^7.0.1",
|
|
9
10
|
"archiver": "^7.0.1",
|
|
11
|
+
"fast-json-stable-stringify": "^2.1.0",
|
|
10
12
|
"get-stream": "^9.0.1",
|
|
11
13
|
"googleapis": "^157.0.0",
|
|
12
14
|
"got": "^14.4.7",
|
|
@@ -57,13 +59,15 @@
|
|
|
57
59
|
"testdocsimages": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocsimages.js execute",
|
|
58
60
|
"testdocsstyles": "cp mainlocal.js main.js && node --env-file=.env ./test/testdocsstyles.js execute",
|
|
59
61
|
"testsandbox": "cp mainlocal.js main.js && node --env-file=.env ./test/testsandbox.js execute",
|
|
62
|
+
"testgmail": "cp mainlocal.js main.js && node --env-file=.env ./test/testgmail.js execute",
|
|
63
|
+
"testlogger": "cp mainlocal.js main.js && node --env-file=.env ./test/testlogger.js execute",
|
|
60
64
|
"pub": "cp mainlocal.js main.js && npm publish --access public"
|
|
61
65
|
},
|
|
62
66
|
"name": "@mcpher/gas-fakes",
|
|
63
|
-
"version": "1.0.
|
|
67
|
+
"version": "1.0.21",
|
|
64
68
|
"license": "MIT",
|
|
65
69
|
"main": "main.js",
|
|
66
70
|
"description": "A proof of concept implementation of Apps Script Environment on Node",
|
|
67
71
|
"repository": "github:brucemcpherson/gas-fakes",
|
|
68
72
|
"homepage": "https://ramblings.mcpher.com/a-proof-of-concept-implementation-of-apps-script-environment-on-node/"
|
|
69
|
-
}
|
|
73
|
+
}
|
package/setup.sh
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# --- 1. Collect Phase ---
|
|
4
|
+
echo "Welcome to the gas-fakes project setup."
|
|
5
|
+
echo "This script will guide you through creating your .env file for testing."
|
|
6
|
+
echo "Please provide the following configuration values."
|
|
7
|
+
echo "Some values are required for the test suite to run correctly."
|
|
8
|
+
echo
|
|
9
|
+
|
|
10
|
+
# --- Required values ---
|
|
11
|
+
read -p "Enter your GCP Project ID: " gcp_project_id
|
|
12
|
+
if [ -z "$gcp_project_id" ]; then
|
|
13
|
+
echo "Error: GCP Project ID is required." >&2
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
read -p "Enter a Drive File ID you have read access to (for testing ADC): " drive_test_file_id
|
|
18
|
+
if [ -z "$drive_test_file_id" ]; then
|
|
19
|
+
echo "Error: Drive File ID is required." >&2
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
read -p "Enter a test Drive Folder Name you have write access to: " test_folder_name
|
|
24
|
+
if [ -z "$test_folder_name" ]; then
|
|
25
|
+
echo "Error: Test Folder Name is required." >&2
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
read -p "Enter the ID of that test Drive Folder: " test_folder_id
|
|
30
|
+
if [ -z "$test_folder_id" ]; then
|
|
31
|
+
echo "Error: Test Folder ID is required." >&2
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# --- Optional values with defaults ---
|
|
36
|
+
read -p "Enter the number of files in that folder [0]: " test_folder_files
|
|
37
|
+
test_folder_files=${test_folder_files:-0}
|
|
38
|
+
|
|
39
|
+
read -p "Enter a viewer email for permission tests [viewer@mcpher.com]: " scratch_viewer
|
|
40
|
+
scratch_viewer=${scratch_viewer:-"viewer@mcpher.com"}
|
|
41
|
+
|
|
42
|
+
read -p "Enter an editor email for permission tests [editor@mcpher.com]: " scratch_editor
|
|
43
|
+
scratch_editor=${scratch_editor:-"editor@mcpher.com"}
|
|
44
|
+
|
|
45
|
+
read -p "Enter a second viewer email [viewer2@mcpher.com]: " scratch_b_viewer
|
|
46
|
+
scratch_b_viewer=${scratch_b_viewer:-"viewer2@mcpher.com"}
|
|
47
|
+
|
|
48
|
+
read -p "Enter a second editor email [editor2@mcpher.com]: " scratch_b_editor
|
|
49
|
+
scratch_b_editor=${scratch_b_editor:-"editor2@mcpher.com"}
|
|
50
|
+
|
|
51
|
+
read -p "Enter min PDFs in root for tests [20]: " min_root_pdfs
|
|
52
|
+
min_root_pdfs=${min_root_pdfs:-20}
|
|
53
|
+
|
|
54
|
+
read -p "Enter min PDFs total for tests [400]: " min_pdfs
|
|
55
|
+
min_pdfs=${min_pdfs:-400}
|
|
56
|
+
|
|
57
|
+
read -p "Enter min folders in root for tests [5]: " min_folders_root
|
|
58
|
+
min_folders_root=${min_folders_root:-5}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# --- 2. Confirm Phase ---
|
|
62
|
+
echo
|
|
63
|
+
echo "The following configuration will be written to .env:"
|
|
64
|
+
echo "================================================="
|
|
65
|
+
echo "# User-specific values"
|
|
66
|
+
echo "GCP_PROJECT_ID=${gcp_project_id}"
|
|
67
|
+
echo "DRIVE_TEST_FILE_ID=${drive_test_file_id}"
|
|
68
|
+
echo "TEST_FOLDER_NAME=\"${test_folder_name}\""
|
|
69
|
+
echo "TEST_FOLDER_ID=${test_folder_id}"
|
|
70
|
+
echo "TEST_FOLDER_FILES=${test_folder_files}"
|
|
71
|
+
echo "SCRATCH_VIEWER=${scratch_viewer}"
|
|
72
|
+
echo "SCRATCH_EDITOR=${scratch_editor}"
|
|
73
|
+
echo "SCRATCH_B_VIEWER=${scratch_b_viewer}"
|
|
74
|
+
echo "SCRATCH_B_EDITOR=${scratch_b_editor}"
|
|
75
|
+
echo "MIN_ROOT_PDFS=${min_root_pdfs}"
|
|
76
|
+
echo "MIN_PDFS=${min_pdfs}"
|
|
77
|
+
echo "MIN_FOLDERS_ROOT=${min_folders_root}"
|
|
78
|
+
echo
|
|
79
|
+
echo "# Shared and static values will also be included."
|
|
80
|
+
echo "================================================="
|
|
81
|
+
echo
|
|
82
|
+
|
|
83
|
+
read -p "Proceed with creating the .env file? (y/N) " confirm
|
|
84
|
+
if [[ ! "$confirm" =~ ^[yY](es)?$ ]]; then
|
|
85
|
+
echo "Setup aborted. No file was written."
|
|
86
|
+
exit 0
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# --- 3. Commit Phase ---
|
|
91
|
+
ENV_FILE=".env"
|
|
92
|
+
TEMP_ENV_FILE="${ENV_FILE}.tmp"
|
|
93
|
+
|
|
94
|
+
# Using a heredoc to write the complete file content.
|
|
95
|
+
cat > "$TEMP_ENV_FILE" << EOL
|
|
96
|
+
# Auto-generated by setup.sh on $(date)
|
|
97
|
+
|
|
98
|
+
# --- User-specific values ---
|
|
99
|
+
# Required for authentication and core tests
|
|
100
|
+
GCP_PROJECT_ID="${gcp_project_id}"
|
|
101
|
+
DRIVE_TEST_FILE_ID="${drive_test_file_id}"
|
|
102
|
+
|
|
103
|
+
# Required for file/folder manipulation tests
|
|
104
|
+
TEST_FOLDER_NAME="${test_folder_name}"
|
|
105
|
+
TEST_FOLDER_ID="${test_folder_id}"
|
|
106
|
+
TEST_FOLDER_FILES=${test_folder_files}
|
|
107
|
+
|
|
108
|
+
# For permission tests
|
|
109
|
+
SCRATCH_VIEWER="${scratch_viewer}"
|
|
110
|
+
SCRATCH_EDITOR="${scratch_editor}"
|
|
111
|
+
SCRATCH_B_VIEWER="${scratch_b_viewer}"
|
|
112
|
+
SCRATCH_B_EDITOR="${scratch_b_editor}"
|
|
113
|
+
|
|
114
|
+
# For iterator/search tests (adjust to your Drive content)
|
|
115
|
+
MIN_ROOT_PDFS=${min_root_pdfs}
|
|
116
|
+
MIN_PDFS=${min_pdfs}
|
|
117
|
+
MIN_FOLDERS_ROOT=${min_folders_root}
|
|
118
|
+
|
|
119
|
+
# --- Static auth config ---
|
|
120
|
+
# we'll use the default config for application default credentials
|
|
121
|
+
# probably dont need to change these
|
|
122
|
+
AC=default
|
|
123
|
+
DEFAULT_SCOPES="https://www.googleapis.com/auth/userinfo.email,openid,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/sqlservice.login"
|
|
124
|
+
EXTRA_SCOPES=",https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/spreadsheets"
|
|
125
|
+
|
|
126
|
+
# --- Shared test file fixtures (read-only) ---
|
|
127
|
+
TEST_BORDERS_ID=1hRGdrYHEPixXTuQLeL3Z0qGRZVs_8ojMIm6D4KrCh1o
|
|
128
|
+
TEST_AIRPORTS_ID=1h9IGIShgVBVUrUjjawk5MaCEQte_7t32XeEP1Z5jXKQ
|
|
129
|
+
TEXT_FILE_NAME="fake.txt"
|
|
130
|
+
TEXT_FILE_ID=1142Vn7W-pGl5nWLpUSkpOB82JDiz9R6p
|
|
131
|
+
TEXT_FILE_TYPE="text/plain"
|
|
132
|
+
TEXT_FILE_CONTENT="foo is not bar"
|
|
133
|
+
TEST_SHEET_ID=1DlKpVVYCrCPNfRbGsz6N_K3oPTgdC9gQIKi0aNb42uI
|
|
134
|
+
TEST_SHEET_NAME="sharedlibraries"
|
|
135
|
+
PDF_ID=17t4ep9Jt6jRyDx0KlxMhHQNGZ3whg6GS
|
|
136
|
+
|
|
137
|
+
# --- Test behavior ---
|
|
138
|
+
# Set to 0 to preserve test files for debugging
|
|
139
|
+
CLEAN=1
|
|
140
|
+
EOL
|
|
141
|
+
|
|
142
|
+
# Atomically rename the temp file to the final .env file.
|
|
143
|
+
mv "$TEMP_ENV_FILE" "$ENV_FILE"
|
|
144
|
+
|
|
145
|
+
echo
|
|
146
|
+
echo "✅ The .env file has been created successfully."
|
|
147
|
+
echo "You can now run 'npm install && npm test' to run the test suite."
|
package/src/index.js
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import './services/scriptapp/app.js'
|
|
2
2
|
import './services/driveapp/app.js'
|
|
3
|
+
import './services/logger/app.js'
|
|
3
4
|
import './services/urlfetchapp/app.js'
|
|
4
5
|
import './services/utilities/app.js'
|
|
5
6
|
import './services/spreadsheetapp/app.js'
|
|
6
7
|
import './services/stores/app.js'
|
|
7
|
-
import './services/
|
|
8
|
+
import './services/gmailapp/app.js'
|
|
9
|
+
import './services/session/app.js'
|
|
8
10
|
import './services/advdrive/app.js'
|
|
9
11
|
import './services/advsheets/app.js'
|
|
10
12
|
import './services/advdocs/app.js'
|
|
13
|
+
import './services/advgmail/app.js'
|
|
11
14
|
import './services/advslides/app.js'
|
|
12
15
|
import './services/documentapp/app.js'
|
|
13
16
|
import './services/advforms/app.js'
|
|
14
17
|
import './services/formapp/app.js'
|
|
15
|
-
import './services/slidesapp/app.js'
|
|
18
|
+
import './services/slidesapp/app.js'
|
|
19
|
+
|
|
20
|
+
// force initilialization of scriptApp - which is always needed
|
|
21
|
+
// scriptapp will always be fake here
|
|
22
|
+
ScriptApp.isFake
|
|
@@ -5,28 +5,9 @@
|
|
|
5
5
|
* We do this by using a proxy, intercepting calls to the
|
|
6
6
|
* initial sigleton and diverting them to a completed one
|
|
7
7
|
*/
|
|
8
|
-
import { newFakeAdvDocs } from './fakeadvdocs.js'
|
|
9
|
-
import {
|
|
8
|
+
import { newFakeAdvDocs as maker } from './fakeadvdocs.js'
|
|
9
|
+
import { lazyLoaderApp } from '../common/lazyloader.js'
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
let _app = null;
|
|
12
|
+
_app = lazyLoaderApp(_app, 'Docs', maker)
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
* adds to global space to mimic Apps Script behavior
|
|
16
|
-
*/
|
|
17
|
-
const name = "Docs"
|
|
18
|
-
if (typeof globalThis[name] === typeof undefined) {
|
|
19
|
-
|
|
20
|
-
const getApp = () => {
|
|
21
|
-
// if it hasne been intialized yet then do that
|
|
22
|
-
if (!_app) {
|
|
23
|
-
console.log('...activating proxy for', name)
|
|
24
|
-
_app = newFakeAdvDocs()
|
|
25
|
-
}
|
|
26
|
-
// this is the actual driveApp we'll return from the proxy
|
|
27
|
-
return _app
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
Proxies.registerProxy(name, getApp)
|
|
31
|
-
|
|
32
|
-
}
|
|
@@ -1,32 +1,10 @@
|
|
|
1
|
-
// fake Apps Script DriveApp
|
|
2
|
-
/**
|
|
3
|
-
* the idea here is to create a global entry for the singleton
|
|
4
|
-
* before we actually have everything we need to create it.
|
|
5
|
-
* We do this by using a proxy, intercepting calls to the
|
|
6
|
-
* initial sigleton and diverting them to a completed one
|
|
7
|
-
*/
|
|
8
|
-
import { newFakeAdvDrive} from './fakeadvdrive.js'
|
|
9
|
-
import { Proxies } from '../../support/proxies.js'
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
let _app = null
|
|
13
1
|
|
|
14
2
|
/**
|
|
15
|
-
*
|
|
3
|
+
* the idea here is to create an empty global entry for the singleton
|
|
4
|
+
* but only load it when it is actually used.
|
|
16
5
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const getApp = () => {
|
|
21
|
-
// if it hasne been intialized yet then do that
|
|
22
|
-
if (!_app) {
|
|
23
|
-
console.log ('...activating proxy for', name)
|
|
24
|
-
_app = newFakeAdvDrive()
|
|
25
|
-
}
|
|
26
|
-
// this is the actual driveApp we'll return from the proxy
|
|
27
|
-
return _app
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
Proxies.registerProxy (name, getApp)
|
|
6
|
+
import { newFakeAdvDrive as maker} from './fakeadvdrive.js'
|
|
7
|
+
import { lazyLoaderApp } from '../common/lazyloader.js'
|
|
31
8
|
|
|
32
|
-
|
|
9
|
+
let _app = null;
|
|
10
|
+
_app = lazyLoaderApp(_app, 'Drive', maker)
|
|
@@ -1,31 +1,12 @@
|
|
|
1
1
|
|
|
2
|
-
/**
|
|
3
|
-
* NOTE - Although Apps Script doesnt yet have a Forms advanced service
|
|
4
|
-
* we're going to funnel everything through here as if there was one.
|
|
5
|
-
*
|
|
6
|
-
*/
|
|
7
|
-
import { newFakeAdvForms } from './fakeadvforms.js'
|
|
8
|
-
import { Proxies } from '../../support/proxies.js'
|
|
9
|
-
|
|
10
|
-
// This will eventually hold a proxy for Formsapp
|
|
11
|
-
let _app = null
|
|
12
2
|
|
|
13
3
|
/**
|
|
14
|
-
*
|
|
4
|
+
* the idea here is to create an empty global entry for the singleton
|
|
5
|
+
* but only load it when it is actually used.
|
|
15
6
|
*/
|
|
16
|
-
const name = "Forms"
|
|
17
|
-
if (typeof globalThis[name] === typeof undefined) {
|
|
18
|
-
|
|
19
|
-
const getApp = () => {
|
|
20
|
-
// if it hasne been intialized yet then do that
|
|
21
|
-
if (!_app) {
|
|
22
|
-
console.log('...activating proxy for', name)
|
|
23
|
-
_app = newFakeAdvForms()
|
|
24
|
-
}
|
|
25
|
-
// this is the actual formsapp we'll return from the proxy
|
|
26
|
-
return _app
|
|
27
|
-
}
|
|
28
7
|
|
|
29
|
-
|
|
8
|
+
import { newFakeAdvForms as maker} from './fakeadvforms.js'
|
|
9
|
+
import { lazyLoaderApp } from '../common/lazyloader.js'
|
|
30
10
|
|
|
31
|
-
|
|
11
|
+
let _app = null;
|
|
12
|
+
_app = lazyLoaderApp(_app, 'Forms', maker)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* the idea here is to create an empty global entry for the singleton
|
|
5
|
+
* but only load it when it is actually used.
|
|
6
|
+
*/
|
|
7
|
+
import { newFakeAdvGmail as maker} from './fakeadvgmail.js'
|
|
8
|
+
import { lazyLoaderApp } from '../common/lazyloader.js'
|
|
9
|
+
|
|
10
|
+
let _app = null;
|
|
11
|
+
_app = lazyLoaderApp(_app, 'Gmail', maker)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Advanced gmail service
|
|
4
|
+
*/
|
|
5
|
+
import { Proxies } from '../../support/proxies.js';
|
|
6
|
+
import { newFakeAdvGmailUsers } from './fakeadvgmailusers.js';
|
|
7
|
+
import { advClassMaker } from '../../support/helpers.js';
|
|
8
|
+
import { gmailCacher } from '../../support/gmailcacher.js';
|
|
9
|
+
|
|
10
|
+
const propsList = { "newModifyMessageRequest": ["addLabelIds", "removeLabelIds"], "newObliterateCseKeyPairRequest": [], "newFilter": ["action", "criteria", "id"], "newHardwareKeyMetadata": ["description"], "newImapSettings": ["autoExpunge", "enabled", "expungeBehavior", "maxFolderSize"], "newDisableCseKeyPairRequest": [], "newFilterAction": ["addLabelIds", "forward", "removeLabelIds"], "newMessagePartHeader": ["name", "value"], "newVacationSettings": ["enableAutoReply", "endTime", "responseBodyHtml", "responseBodyPlainText", "responseSubject", "restrictToContacts", "restrictToDomain", "startTime"], "newFilterCriteria": ["excludeChats", "from", "hasAttachment", "negatedQuery", "query", "size", "sizeComparison", "subject", "to"], "newModifyThreadRequest": ["addLabelIds", "removeLabelIds"], "newSmimeInfo": ["encryptedKeyPassword", "expiration", "id", "isDefault", "issuerCn", "pem", "pkcs12"], "newMessage": ["historyId", "id", "internalDate", "labelIds", "payload", "raw", "sizeEstimate", "snippet", "threadId"], "newMessagePartBody": ["attachmentId", "data", "size"], "newBatchDeleteMessagesRequest": ["ids"], "newCsePrivateKeyMetadata": ["hardwareKeyMetadata", "kaclsKeyMetadata", "privateKeyMetadataId"], "newAutoForwarding": ["disposition", "emailAddress", "enabled"], "newLabelColor": ["backgroundColor", "textColor"], "newLanguageSettings": ["displayLanguage"], "newBatchModifyMessagesRequest": ["addLabelIds", "ids", "removeLabelIds"], "newForwardingAddress": ["forwardingEmail", "verificationStatus"], "newSignAndEncryptKeyPairs": ["encryptionKeyPairId", "signingKeyPairId"], "newSendAs": ["displayName", "isDefault", "isPrimary", "replyToAddress", "sendAsEmail", "signature", "smtpMsa", "treatAsAlias", "verificationStatus"], "newSmtpMsa": ["host", "password", "port", "securityMode", "username"], "newMessagePart": ["body", "filename", "headers", "mimeType", "partId", "parts"], "newLabel": ["color", "id", "labelListVisibility", "messageListVisibility", "messagesTotal", "messagesUnread", "name", "threadsTotal", "threadsUnread", "type"], "newWatchRequest": ["labelFilterAction", "labelFilterBehavior", "labelIds", "topicName"], "newKaclsKeyMetadata": ["kaclsData", "kaclsUri"], "newEnableCseKeyPairRequest": [], "newDraft": ["id", "message"], "newPopSettings": ["accessWindow", "disposition"], "newDelegate": ["delegateEmail", "verificationStatus"], "newCseIdentity": ["emailAddress", "primaryKeyPairId", "signAndEncryptKeyPairs"], "newCseKeyPair": ["disableTime", "enablementState", "keyPairId", "pem", "pkcs7", "privateKeyMetadata", "subjectEmailAddresses"] }
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FakeAdvGmail {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.__fakeObjectType = "Gmail"
|
|
16
|
+
|
|
17
|
+
Reflect.ownKeys(propsList).forEach(p => {
|
|
18
|
+
this[p] = () => advClassMaker(propsList[p])
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
toString() {
|
|
23
|
+
return 'AdvancedServiceIdentifier{name=gmail, version=v1}'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getVersion() {
|
|
27
|
+
return 'v1'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get Users() {
|
|
31
|
+
return newFakeAdvGmailUsers(this)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
__getGmailPerformance() {
|
|
35
|
+
return gmailCacher.getPerformance()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const newFakeAdvGmail = (...args) => Proxies.guard(new FakeAdvGmail(...args))
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { FakeAdvResource } from '../common/fakeadvresource.js';
|
|
2
|
+
import { Proxies } from '../../support/proxies.js';
|
|
3
|
+
import { gError, normalizeSerialization } from '../../support/helpers.js';
|
|
4
|
+
import { Syncit } from '../../support/syncit.js';
|
|
5
|
+
|
|
6
|
+
export const newFakeAdvGmailLabels = (...args) => Proxies.guard(new FakeAdvGmailLabels(...args));
|
|
7
|
+
|
|
8
|
+
class FakeAdvGmailLabels extends FakeAdvResource {
|
|
9
|
+
constructor(mainService) {
|
|
10
|
+
super(mainService, 'users', Syncit.fxGmail);
|
|
11
|
+
this.gmail = mainService;
|
|
12
|
+
this.__fakeObjectType = 'Gmail.Users.Labels';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new label.
|
|
17
|
+
* @param {object} resource - The label resource to create.
|
|
18
|
+
* @param {string} userId - The user's email address. The special value me can be used to indicate the authenticated user.
|
|
19
|
+
* @returns {object} The created label resource.
|
|
20
|
+
*/
|
|
21
|
+
create(resource, userId) {
|
|
22
|
+
const { data, response } = this._call(
|
|
23
|
+
'create',
|
|
24
|
+
{ userId, requestBody: normalizeSerialization(resource) },
|
|
25
|
+
null,
|
|
26
|
+
'labels'
|
|
27
|
+
);
|
|
28
|
+
gError(response, 'gmail', 'users.labels.create');
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Deletes the specified label.
|
|
34
|
+
* @param {string} userId - The user's email address. The special value me can be used to indicate the authenticated user.
|
|
35
|
+
* @param {string} id - The ID of the label to delete.
|
|
36
|
+
*/
|
|
37
|
+
remove(userId, id) {
|
|
38
|
+
const { data, response } = this._call(
|
|
39
|
+
'delete',
|
|
40
|
+
{ userId, id },
|
|
41
|
+
null,
|
|
42
|
+
'labels'
|
|
43
|
+
);
|
|
44
|
+
gError(response, 'gmail', 'users.labels.delete');
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Gets the specified label.
|
|
50
|
+
* @param {string} userId - The user's email address. The special value me can be used to indicate the authenticated user.
|
|
51
|
+
* @param {string} id - The ID of the label to retrieve.
|
|
52
|
+
* @returns {object} The label resource.
|
|
53
|
+
*/
|
|
54
|
+
get(userId, id) {
|
|
55
|
+
const { data, response } = this._call(
|
|
56
|
+
'get',
|
|
57
|
+
{ userId, id },
|
|
58
|
+
null,
|
|
59
|
+
'labels'
|
|
60
|
+
);
|
|
61
|
+
gError(response, 'gmail', 'users.labels.get', true);
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Lists all labels in the user's mailbox.
|
|
67
|
+
* @param {string} userId - The user's email address. The special value me can be used to indicate the authenticated user.
|
|
68
|
+
* @param {object} params - The parameters for the request.
|
|
69
|
+
* @returns {object} A list of labels.
|
|
70
|
+
*/
|
|
71
|
+
list(userId, params = {}) {
|
|
72
|
+
const { data, response } = this._call(
|
|
73
|
+
'list',
|
|
74
|
+
{ ...params, userId },
|
|
75
|
+
null,
|
|
76
|
+
'labels'
|
|
77
|
+
);
|
|
78
|
+
gError(response, 'gmail', 'users.labels.list');
|
|
79
|
+
return data;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Updates the specified label. This method supports patch semantics.
|
|
84
|
+
* @param {string} userId - The user's email address. The special value me can be used to indicate the authenticated user.
|
|
85
|
+
* @param {object} resource - The label resource to update.
|
|
86
|
+
* @param {object} [params={}] - The parameters for the request.
|
|
87
|
+
* @param {string} params.id - The ID of the label to update.
|
|
88
|
+
* @returns {object} The updated label resource.
|
|
89
|
+
*/
|
|
90
|
+
patch(userId, resource, params = {}) {
|
|
91
|
+
const { data, response } = this._call(
|
|
92
|
+
'patch',
|
|
93
|
+
{ ...params, userId, requestBody: normalizeSerialization(resource) },
|
|
94
|
+
null,
|
|
95
|
+
'labels'
|
|
96
|
+
);
|
|
97
|
+
gError(response, 'gmail', 'users.labels.patch');
|
|
98
|
+
return data;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Updates the specified label.
|
|
103
|
+
* @param {string} userId - The user's email address. The special value me can be used to indicate the authenticated user.
|
|
104
|
+
* @param {object} resource - The label resource to update.
|
|
105
|
+
* @param {object} [params={}] - The parameters for the request.
|
|
106
|
+
* @param {string} params.id - The ID of the label to update.
|
|
107
|
+
* @returns {object} The updated label resource.
|
|
108
|
+
*/
|
|
109
|
+
update(userId, resource, params = {}) {
|
|
110
|
+
const { data, response } = this._call(
|
|
111
|
+
'update',
|
|
112
|
+
{ ...params, userId, requestBody: normalizeSerialization(resource) },
|
|
113
|
+
null,
|
|
114
|
+
'labels'
|
|
115
|
+
);
|
|
116
|
+
gError(response, 'gmail', 'users.labels.update');
|
|
117
|
+
return data;
|
|
118
|
+
}
|
|
119
|
+
}
|