@mcpher/gas-fakes 2.2.5 → 2.2.6

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/package.json CHANGED
@@ -15,6 +15,7 @@
15
15
  "dotenv": "^17.3.1",
16
16
  "fast-xml-parser": "^5.4.2",
17
17
  "get-stream": "^9.0.1",
18
+ "google-auth-library": "^10.6.2",
18
19
  "googleapis": "^171.4.0",
19
20
  "got": "^14.6.6",
20
21
  "into-stream": "^9.1.0",
@@ -26,6 +27,9 @@
26
27
  "unzipper": "^0.12.3",
27
28
  "zod": "^4.3.6"
28
29
  },
30
+ "overrides": {
31
+ "glob": "^13.0.6"
32
+ },
29
33
  "type": "module",
30
34
  "scripts": {
31
35
  "pub": "npm publish --access public",
@@ -35,7 +39,7 @@
35
39
  },
36
40
  "name": "@mcpher/gas-fakes",
37
41
  "author": "bruce mcpherson",
38
- "version": "2.2.5",
42
+ "version": "2.2.6",
39
43
  "license": "MIT",
40
44
  "main": "main.js",
41
45
  "description": "An implementation of the Google Workspace Apps Script runtime: Run native App Script Code on Node and Cloud Run",
@@ -44,4 +48,4 @@
44
48
  "bin": {
45
49
  "gas-fakes": "gas-fakes.js"
46
50
  }
47
- }
51
+ }
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  InteractiveBrowserCredential,
3
- ClientSecretCredential
3
+ ClientSecretCredential,
4
+ useIdentityPlugin
4
5
  } from "@azure/identity";
6
+
5
7
  import { execSync } from 'node:child_process';
6
8
  import { readFile, writeFile } from 'fs/promises';
7
9
  import { existsSync } from 'fs';
@@ -40,20 +42,66 @@ function decodeJWT(token) {
40
42
  return JSON.parse(Buffer.from(encodedPayload, 'base64url').toString('utf-8'));
41
43
  }
42
44
 
45
+ const customCachePlugin = (options) => {
46
+ return {
47
+ beforeCacheAccess: async (cacheContext) => {
48
+ if (existsSync(TOKEN_CACHE_FILE)) {
49
+ try {
50
+ const data = await readFile(TOKEN_CACHE_FILE, 'utf-8');
51
+ let cache;
52
+ if (data.trim().startsWith('{')) {
53
+ cache = JSON.parse(data);
54
+ } else {
55
+ cache = decodeJWT(data.trim());
56
+ }
57
+ if (cache && cache.msalCache) {
58
+ cacheContext.tokenCache.deserialize(cache.msalCache);
59
+ }
60
+ } catch (e) {
61
+ console.warn(`...failed to load MS Graph token cache: ${e.message}`);
62
+ }
63
+ }
64
+ },
65
+ afterCacheAccess: async (cacheContext) => {
66
+ if (cacheContext.cacheHasChanged) {
67
+ try {
68
+ const msalCache = cacheContext.tokenCache.serialize();
69
+ const cacheData = {
70
+ msalCache,
71
+ token: 'managed-by-msal',
72
+ expiresOn: new Date(Date.now() + 86400000 * 30).getTime() // Keep valid for 30 days
73
+ };
74
+ const jwtString = encodeJWT(cacheData);
75
+ await writeFile(TOKEN_CACHE_FILE, jwtString);
76
+ try {
77
+ chmodSync(TOKEN_CACHE_FILE, 0o600);
78
+ } catch (e) {}
79
+ } catch (e) {
80
+ console.warn(`...failed to save MS Graph token cache: ${e.message}`);
81
+ }
82
+ }
83
+ }
84
+ };
85
+ };
86
+
87
+ useIdentityPlugin((context) => {
88
+ if (context.cachePluginControl) {
89
+ context.cachePluginControl.setPersistence(customCachePlugin);
90
+ }
91
+ });
92
+
43
93
  async function loadTokenCache() {
44
94
  if (existsSync(TOKEN_CACHE_FILE)) {
45
95
  try {
46
96
  const data = await readFile(TOKEN_CACHE_FILE, 'utf-8');
47
97
 
48
98
  let cache;
49
- // Handle legacy plain-text JSON format gracefully
50
99
  if (data.trim().startsWith('{')) {
51
100
  cache = JSON.parse(data);
52
101
  } else {
53
102
  cache = decodeJWT(data.trim());
54
103
  }
55
104
 
56
- // Check if expired (buffer of 5 mins)
57
105
  if (cache && cache.expiresOn && new Date(cache.expiresOn).getTime() > Date.now() + 300000) {
58
106
  return cache.token;
59
107
  }
@@ -70,10 +118,8 @@ async function saveTokenCache(token, expiresOn) {
70
118
  const jwtString = encodeJWT(cacheData);
71
119
  await writeFile(TOKEN_CACHE_FILE, jwtString);
72
120
  try {
73
- chmodSync(TOKEN_CACHE_FILE, 0o600); // Read/Write only for owner
74
- } catch (e) {
75
- // Ignore if chmod fails (e.g. on non-posix)
76
- }
121
+ chmodSync(TOKEN_CACHE_FILE, 0o600);
122
+ } catch (e) {}
77
123
  } catch (e) {
78
124
  console.warn(`...failed to save MS Graph token cache: ${e.message}`);
79
125
  }
@@ -230,7 +276,11 @@ export async function getMsGraphToken(scopes = ['User.Read']) {
230
276
  const credentialSilent = new InteractiveBrowserCredential({
231
277
  tenantId: (envTenant && envTenant !== 'common') ? envTenant : 'consumers',
232
278
  clientId,
233
- prompt: promptBehavior
279
+ prompt: promptBehavior,
280
+ tokenCachePersistenceOptions: {
281
+ enabled: true,
282
+ name: 'gas-fakes-msgraph-cache'
283
+ }
234
284
  });
235
285
 
236
286
  try {
@@ -244,7 +294,11 @@ export async function getMsGraphToken(scopes = ['User.Read']) {
244
294
  const credentialInteractive = new InteractiveBrowserCredential({
245
295
  tenantId: (envTenant && envTenant !== 'common') ? envTenant : 'consumers',
246
296
  clientId,
247
- prompt: 'select_account consent'
297
+ prompt: 'select_account consent',
298
+ tokenCachePersistenceOptions: {
299
+ enabled: true,
300
+ name: 'gas-fakes-msgraph-cache'
301
+ }
248
302
  });
249
303
  const tokenResponse = await credentialInteractive.getToken(msScopes);
250
304
  syncLog('...retrieved MS Graph token via interactive login');
package/exgcp.sh DELETED
@@ -1,54 +0,0 @@
1
- #!/bin/bash
2
-
3
- # This script reads the GCP_PROJECT_ID from a .env file
4
- # and exports it as GOOGLE_CLOUD_PROJECT for the current shell session.
5
- #
6
- # Usage: source . ./exgcp.sh
7
-
8
- # Define the path to your .env file relative to the script's location
9
- ENV_FILE="$(dirname "$0")/.env"
10
-
11
- # Check if the .env file exists
12
-
13
- if [ ! -f "$ENV_FILE" ]; then
14
- echo "Error: .env file not found at path: $ENV_FILE"
15
- # Use 'return' instead of 'exit' so it doesn't close the user's terminal when sourced
16
- return 1
17
- fi
18
-
19
- # Read the GCP_PROJECT_ID, remove quotes, and handle potential carriage returns
20
- GOOGLE_CLOUD_PROJECT_VALUE=$(grep -E '^GOOGLE_CLOUD_PROJECT=' "$ENV_FILE" | cut -d '=' -f2 | tr -d '"\r')
21
- GEMINI_API_KEY_VALUE=$(grep -E '^GEMINI_API_KEY=' "$ENV_FILE" | cut -d '=' -f2 | tr -d '"\r')
22
- GEMINI_MODEL_VALUE=$(grep -E '^GEMINI_MODEL=' "$ENV_FILE" | cut -d '=' -f2 | tr -d '"\r')
23
- OMDB_API_KEY_VALUE=$(grep -E '^OMDB_API_KEY=' "$ENV_FILE" | cut -d '=' -f2 | tr -d '"\r')
24
- # Check if a value was extracted
25
- if [ -z "$GOOGLE_CLOUD_PROJECT_VALUE" ]; then
26
- echo "Error: GOOGLE_CLOUD_PROJECT not found or is empty in $ENV_FILE."
27
- return 1
28
- fi
29
-
30
- if [ -z "GEMINI_API_KEY_VALUE" ]; then
31
- echo "GEMINI_API_KEY not found or is empty in $ENV_FILE."
32
- else
33
- echo "exported: GEMINI_API_KEY"
34
- export GEMINI_API_KEY="$GEMINI_API_KEY_VALUE"
35
- fi
36
-
37
- if [ -z "OMDB_API_KEY_VALUE" ]; then
38
- echo "OMDB_API_KEY not found or is empty in $ENV_FILE."
39
- else
40
- echo "exported: OMDB_API_KEY"
41
- export OMDB_API_KEY="$OMDB_API_KEY_VALUE"
42
- fi
43
-
44
- if [ -z "GEMINI_MODEL_VALUE" ]; then
45
- echo "GEMINI_MODEL not found or is empty in $ENV_FILE."
46
- else
47
- echo "exported: GEMINI_MODEL=$GEMINI_MODEL_VALUE"
48
- export GEMINI_MODEL="$GEMINI_MODEL_VALUE"
49
- fi
50
-
51
- # Export the variable for the current session
52
- export GOOGLE_CLOUD_PROJECT="$GOOGLE_CLOUD_PROJECT_VALUE"
53
-
54
- echo "exported: GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT"
package/introvideo.png DELETED
Binary file
package/logo.png DELETED
Binary file
package/plain-logo.png DELETED
Binary file
package/testlib.sh DELETED
@@ -1,2 +0,0 @@
1
- gas-fakes -l bmFiddler@13EWG4-lPrEf34itxQhAQ7b9JEbmCBfO8uE4Mhr99CHi3Pw65oxXtq-rU \
2
- -s "const sheet=SpreadsheetApp.openById('1h9IGIShgVBVUrUjjawk5MaCEQte_7t32XeEP1Z5jXKQ').getSheets()[0];const fiddler = new bmFiddler.Fiddler(sheet);console.log (fiddler.getData().slice(0, 5));"